From d3f69ab4c6d4f1e2eb3349eec3f1cb9313081151 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 7 Mar 2021 08:43:01 +0100 Subject: documentation for AFL_PERSISTENT_RECORD --- docs/env_variables.md | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index 4c3b1cfb..41733f1b 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -400,6 +400,15 @@ 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)) + 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 + with a value of how many previous fuzz cases to keep prio a crash. + if set to e.g. 10, then the 9 previous inputs are written to + out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 + and RECORD:000000,cnt:000009 being the crash case. + - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`. Others need not apply. -- cgit 1.4.1 From ee5078f43c44a022831cf83b6963930975188168 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 11:22:37 +0100 Subject: v3.13a init --- docs/Changelog.md | 3 +++ include/config.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 5b7d6ab6..6b7ebf15 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.13a (development) + - ... + ### Version ++3.12c (release) - afl-fuzz: - added AFL_TARGET_ENV variable to pass extra env vars to the target diff --git a/include/config.h b/include/config.h index c93a6d51..8ac74c45 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.12c" +#define VERSION "++3.13a" /****************************************************** * * -- cgit 1.4.1 From 836aeef595462a37f6be4665a5a6123002423b41 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 24 Mar 2021 18:22:50 +0100 Subject: changelog info --- docs/Changelog.md | 7 ++++++- docs/env_variables.md | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6b7ebf15..caa06ffd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,12 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) - - ... + - afl-fuzz: + - added patch by @realmadsci to support @@ as part of command line + options, e.g. `afl-fuzz ... -- ./target --infile=@@` + - add recording of previous fuzz attempts for persistent mode + to allow replay of non-reproducable crashes, see + AFL_PERSISTENT_RECORD in config.h and docs/envs.h ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index de6b4bd8..6d3d1714 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -432,6 +432,7 @@ checks or alter some of the more exotic semantics of the tool: if set to e.g. 10, then the 9 previous inputs are written to out/default/crashes as RECORD:000000,cnt:000000 to RECORD:000000,cnt:000008 and RECORD:000000,cnt:000009 being the crash case. + NOTE: This option needs to be enabled in config.h first! - If you are Jakub, you may need `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`. Others need not apply, unless they also want to disable the -- cgit 1.4.1 From 447d232caf9fcd9e6e40c24d17000ff9b98ab693 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 08:55:41 +0100 Subject: update changelog --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index caa06ffd..87ac858e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - default cmplog level (-l) is now 2, better efficiency. ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From 0029c1a83ef03825c2d19c73151189f159458496 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 15:35:06 +0100 Subject: remove InsTrim --- GNUmakefile.llvm | 5 +- README.md | 1 - docs/Changelog.md | 2 + docs/PATCHES.md | 43 --- docs/env_variables.md | 27 +- docs/perf_tips.md | 3 - instrumentation/LLVMInsTrim.so.cc | 599 ------------------------------------- instrumentation/MarkNodes.cc | 481 ----------------------------- instrumentation/MarkNodes.h | 12 - instrumentation/README.instrim.md | 30 -- instrumentation/README.llvm.md | 17 +- instrumentation/README.snapshot.md | 2 + src/afl-cc.c | 50 +--- src/afl-ld-lto.c | 20 +- test/test-llvm.sh | 21 -- 15 files changed, 29 insertions(+), 1284 deletions(-) delete mode 100644 docs/PATCHES.md delete mode 100644 instrumentation/LLVMInsTrim.so.cc delete mode 100644 instrumentation/MarkNodes.cc delete mode 100644 instrumentation/MarkNodes.h delete mode 100644 instrumentation/README.instrim.md (limited to 'docs') diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 111a847d..4b5ac520 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -304,7 +304,7 @@ ifeq "$(TEST_MMAP)" "1" endif PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o -PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so +PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so # If prerequisites are not given, warn, do not build anything, and exit with code 0 ifeq "$(LLVMVER)" "" @@ -382,9 +382,6 @@ endif instrumentation/afl-llvm-common.o: instrumentation/afl-llvm-common.cc instrumentation/afl-llvm-common.h $(CXX) $(CFLAGS) $(CPPFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ -./libLLVMInsTrim.so: instrumentation/LLVMInsTrim.so.cc instrumentation/MarkNodes.cc instrumentation/afl-llvm-common.o | test_deps - -$(CXX) $(CLANG_CPPFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< instrumentation/MarkNodes.cc -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o - ./afl-llvm-pass.so: instrumentation/afl-llvm-pass.so.cc instrumentation/afl-llvm-common.o | test_deps ifeq "$(LLVM_MIN_4_0_1)" "0" $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER)) diff --git a/README.md b/README.md index 2de35d11..3ba05777 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,6 @@ There are many more options and modes available however these are most of the time less effective. See: * [instrumentation/README.ctx.md](instrumentation/README.ctx.md) * [instrumentation/README.ngram.md](instrumentation/README.ngram.md) - * [instrumentation/README.instrim.md](instrumentation/README.instrim.md) afl++ performs "never zero" counting in its bitmap. You can read more about this here: diff --git a/docs/Changelog.md b/docs/Changelog.md index 87ac858e..730791da 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,8 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - afl-cc: + - Removed InsTrim instrumentation as it is not as good as PCGUARD ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/PATCHES.md b/docs/PATCHES.md deleted file mode 100644 index b2cff43a..00000000 --- a/docs/PATCHES.md +++ /dev/null @@ -1,43 +0,0 @@ -# Applied Patches - -The following patches from https://github.com/vanhauser-thc/afl-patches -have been installed or not installed: - - -## INSTALLED -``` -afl-llvm-fix.diff by kcwu(at)csie(dot)org -afl-sort-all_uniq-fix.diff by legarrec(dot)vincent(at)gmail(dot)com -laf-intel.diff by heiko(dot)eissfeldt(at)hexco(dot)de -afl-llvm-optimize.diff by mh(at)mh-sec(dot)de -afl-fuzz-tmpdir.diff by mh(at)mh-sec(dot)de -afl-fuzz-79x24.diff by heiko(dot)eissfeldt(at)hexco(dot)de -afl-fuzz-fileextensionopt.diff tbd -afl-as-AFL_INST_RATIO.diff by legarrec(dot)vincent(at)gmail(dot)com -afl-qemu-ppc64.diff by william(dot)barsse(at)airbus(dot)com -afl-qemu-optimize-entrypoint.diff by mh(at)mh-sec(dot)de -afl-qemu-speed.diff by abiondo on github -afl-qemu-optimize-map.diff by mh(at)mh-sec(dot)de -``` - -+ llvm_mode ngram prev_loc coverage (github.com/adrianherrera/afl-ngram-pass) -+ Custom mutator (native library) (by kyakdan) -+ unicorn_mode (modernized and updated by domenukk) -+ instrim (https://github.com/csienslab/instrim) was integrated -+ MOpt (github.com/puppet-meteor/MOpt-AFL) was imported -+ AFLfast additions (github.com/mboehme/aflfast) were incorporated. -+ Qemu 3.1 upgrade with enhancement patches (github.com/andreafioraldi/afl) -+ Python mutator modules support (github.com/choller/afl) -+ Instrument file list in LLVM mode (github.com/choller/afl) -+ forkserver patch for afl-tmin (github.com/nccgroup/TriforceAFL) - - -## NOT INSTALLED - -``` -afl-fuzz-context_sensitive.diff - changes too much of the behaviour -afl-tmpfs.diff - same as afl-fuzz-tmpdir.diff but more complex -afl-cmin-reduce-dataset.diff - unsure of the impact -afl-llvm-fix2.diff - not needed with the other patches -``` - diff --git a/docs/env_variables.md b/docs/env_variables.md index 6d3d1714..572fad01 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -130,16 +130,15 @@ Then there are a few specific features that are only available in instrumentatio PCGUARD - our own pcgard based instrumentation (default) NATIVE - clang's original pcguard based instrumentation CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default) - CFG - InsTrim instrumentation (see below) LTO - LTO instrumentation (see below) CTX - context sensitive instrumentation (see below) NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) GCC - outdated gcc instrumentation CLANG - outdated clang instrumentation - In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or - NGRAM, seperate the options with a comma "," then, e.g.: - `AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4` - Not that this is a good idea to use both CTX and NGRAM :) + In CLASSIC you can also specify CTX and/or NGRAM, seperate the options + with a comma "," then, e.g.: + `AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4` + Note that this is actually not a good idea to use both CTX and NGRAM :) ### LTO @@ -173,24 +172,6 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information. -### INSTRIM - - 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` activates this mode - - - Setting `AFL_LLVM_INSTRIM_LOOPHEAD=1` expands on INSTRIM to optimize loops. - 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). - - See [instrumentation/README.instrim.md](../instrumentation/README.instrim.md) - ### NGRAM - Setting `AFL_LLVM_NGRAM_SIZE` or `AFL_LLVM_INSTRUMENT=NGRAM-{value}` diff --git a/docs/perf_tips.md b/docs/perf_tips.md index fbcb4d8d..c5968206 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -69,9 +69,6 @@ If you are only interested in specific parts of the code being fuzzed, you can instrument_files the files that are actually relevant. This improves the speed and accuracy of afl. See instrumentation/README.instrument_list.md -Also use the InsTrim mode on larger binaries, this improves performance and -coverage a lot. - ## 4. Profile and optimize the binary Check for any parameters or settings that obviously improve performance. For diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc deleted file mode 100644 index 62de6ec5..00000000 --- a/instrumentation/LLVMInsTrim.so.cc +++ /dev/null @@ -1,599 +0,0 @@ -#include -#include -#include -#include - -#include "llvm/Config/llvm-config.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 -typedef long double max_align_t; -#endif - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) - #include "llvm/IR/CFG.h" - #include "llvm/IR/Dominators.h" - #include "llvm/IR/DebugInfo.h" -#else - #include "llvm/Support/CFG.h" - #include "llvm/Analysis/Dominators.h" - #include "llvm/DebugInfo.h" -#endif -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/IR/BasicBlock.h" -#include -#include -#include -#include -#include - -#include "MarkNodes.h" -#include "afl-llvm-common.h" -#include "llvm-alternative-coverage.h" - -#include "config.h" -#include "debug.h" - -using namespace llvm; - -static cl::opt MarkSetOpt("markset", cl::desc("MarkSet"), - cl::init(false)); -static cl::opt LoopHeadOpt("loophead", cl::desc("LoopHead"), - cl::init(false)); - -namespace { - -struct InsTrim : public ModulePass { - - protected: - uint32_t function_minimum_size = 1; - char * skip_nozero = NULL; - - private: - std::mt19937 generator; - int total_instr = 0; - - unsigned int genLabel() { - - return generator() & (MAP_SIZE - 1); - - } - - public: - static char ID; - - InsTrim() : ModulePass(ID), generator(0) { - - initInstrumentList(); - - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - - AU.addRequired(); - - } - -#if LLVM_VERSION_MAJOR < 4 - const char * -#else - StringRef -#endif - getPassName() const override { - - return "InstTrim Instrumentation"; - - } - -#if LLVM_VERSION_MAJOR > 4 || \ - (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) - #define AFL_HAVE_VECTOR_INTRINSICS 1 -#endif - - bool runOnModule(Module &M) override { - - setvbuf(stdout, NULL, _IONBF, 0); - - if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { - - SAYF(cCYA "LLVMInsTrim" VERSION cRST " by csienslab\n"); - - } else - - be_quiet = 1; - - if (getenv("AFL_DEBUG") != NULL) debug = 1; - - LLVMContext &C = M.getContext(); - - IntegerType *Int8Ty = IntegerType::getInt8Ty(C); - IntegerType *Int32Ty = IntegerType::getInt32Ty(C); - -#if LLVM_VERSION_MAJOR < 9 - char *neverZero_counters_str; - if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL) - if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n"); -#endif - skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); - - if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL || - getenv("LOOPHEAD") != NULL) { - - LoopHeadOpt = true; - - } - - unsigned int PrevLocSize = 0; - char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); - if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); - char *caller_str = getenv("AFL_LLVM_CALLER"); - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - unsigned int ngram_size = 0; - /* Decide previous location vector size (must be a power of two) */ - VectorType *PrevLocTy = NULL; - - if (ngram_size_str) - if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 || - ngram_size > NGRAM_SIZE_MAX) - FATAL( - "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX " - "(%u))", - NGRAM_SIZE_MAX); - - if (ngram_size) - PrevLocSize = ngram_size - 1; - else -#else - if (ngram_size_str) - #ifdef LLVM_VERSION_STRING - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version %s!", - LLVM_VERSION_STRING); - #else - #ifndef LLVM_VERSION_PATCH - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version " - "%d.%d.%d!", - LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, 0); - #else - FATAL( - "Sorry, NGRAM branch coverage is not supported with llvm version " - "%d.%d.%d!", - LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERISON_PATCH); - #endif - #endif -#endif - PrevLocSize = 1; - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - // IntegerType *Int64Ty = IntegerType::getInt64Ty(C); - int PrevLocVecSize = PowerOf2Ceil(PrevLocSize); - IntegerType *IntLocTy = - IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT); - if (ngram_size) - PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize - #if LLVM_VERSION_MAJOR >= 12 - , - false - #endif - ); -#endif - - /* Get globals for the SHM region and the previous location. Note that - __afl_prev_loc is thread-local. */ - - GlobalVariable *AFLMapPtr = - new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, - GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); - GlobalVariable *AFLPrevLoc; - GlobalVariable *AFLContext = NULL; - LoadInst * PrevCaller = NULL; // for CALLER sensitive coverage - - if (caller_str) -#if defined(__ANDROID__) || defined(__HAIKU__) - AFLContext = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); -#else - AFLContext = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", - 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); -#endif - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) - #if defined(__ANDROID__) || defined(__HAIKU__) - AFLPrevLoc = new GlobalVariable( - M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, - /* Initializer */ nullptr, "__afl_prev_loc"); - #else - AFLPrevLoc = new GlobalVariable( - M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, - /* Initializer */ nullptr, "__afl_prev_loc", - /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel, - /* AddressSpace */ 0, /* IsExternallyInitialized */ false); - #endif - else -#endif -#if defined(__ANDROID__) || defined(__HAIKU__) - AFLPrevLoc = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); -#else - AFLPrevLoc = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0, - GlobalVariable::GeneralDynamicTLSModel, 0, false); -#endif - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - /* Create the vector shuffle mask for updating the previous block history. - Note that the first element of the vector will store cur_loc, so just set - it to undef to allow the optimizer to do its thing. */ - - SmallVector PrevLocShuffle = {UndefValue::get(Int32Ty)}; - - for (unsigned I = 0; I < PrevLocSize - 1; ++I) - PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I)); - - for (int I = PrevLocSize; I < PrevLocVecSize; ++I) - PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize)); - - Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle); -#endif - - // this is our default - MarkSetOpt = true; - - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); - ConstantInt *One = ConstantInt::get(Int8Ty, 1); - - u64 total_rs = 0; - u64 total_hs = 0; - - scanForDangerousFunctions(&M); - - for (Function &F : M) { - - if (debug) { - - uint32_t bb_cnt = 0; - - for (auto &BB : F) - if (BB.size() > 0) ++bb_cnt; - DEBUGF("Function %s size %zu %u\n", F.getName().str().c_str(), F.size(), - bb_cnt); - - } - - if (!isInInstrumentList(&F)) continue; - - // if the function below our minimum size skip it (1 or 2) - if (F.size() < function_minimum_size) { continue; } - - std::unordered_set MS; - if (!MarkSetOpt) { - - for (auto &BB : F) { - - MS.insert(&BB); - - } - - total_rs += F.size(); - - } else { - - auto Result = markNodes(&F); - auto RS = Result.first; - auto HS = Result.second; - - MS.insert(RS.begin(), RS.end()); - if (!LoopHeadOpt) { - - MS.insert(HS.begin(), HS.end()); - total_rs += MS.size(); - - } else { - - DenseSet> EdgeSet; - DominatorTreeWrapperPass * DTWP = - &getAnalysis(F); - auto DT = &DTWP->getDomTree(); - - total_rs += RS.size(); - total_hs += HS.size(); - - for (BasicBlock *BB : HS) { - - bool Inserted = false; - for (auto BI = pred_begin(BB), BE = pred_end(BB); BI != BE; ++BI) { - - auto Edge = BasicBlockEdge(*BI, BB); - if (Edge.isSingleEdge() && DT->dominates(Edge, BB)) { - - EdgeSet.insert({*BI, BB}); - Inserted = true; - break; - - } - - } - - if (!Inserted) { - - MS.insert(BB); - total_rs += 1; - total_hs -= 1; - - } - - } - - for (auto I = EdgeSet.begin(), E = EdgeSet.end(); I != E; ++I) { - - auto PredBB = I->first; - auto SuccBB = I->second; - auto NewBB = - SplitBlockPredecessors(SuccBB, {PredBB}, ".split", DT, nullptr, -#if LLVM_VERSION_MAJOR >= 8 - nullptr, -#endif - false); - MS.insert(NewBB); - - } - - } - - for (BasicBlock &BB : F) { - - if (MS.find(&BB) == MS.end()) { continue; } - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) { - - LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); - PrevLoc->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - Value *ShuffledPrevLoc = IRB.CreateShuffleVector( - PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask); - Value *UpdatedPrevLoc = IRB.CreateInsertElement( - ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()), - (uint64_t)0); - - IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc) - ->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } else - -#endif - { - - IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc); - - } - - } - - } - - int has_calls = 0; - for (BasicBlock &BB : F) { - - auto PI = pred_begin(&BB); - auto PE = pred_end(&BB); - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - Value * L = NULL; - unsigned int cur_loc; - - // Context sensitive coverage - if (caller_str && &BB == &F.getEntryBlock()) { - - PrevCaller = IRB.CreateLoad(AFLContext); - PrevCaller->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - // does the function have calls? and is any of the calls larger than - // one basic block? - has_calls = 0; - for (auto &BB2 : F) { - - if (has_calls) break; - for (auto &IN : BB2) { - - CallInst *callInst = nullptr; - if ((callInst = dyn_cast(&IN))) { - - Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < function_minimum_size) - continue; - else { - - has_calls = 1; - break; - - } - - } - - } - - } - - // if yes we store a context ID for this function in the global var - if (has_calls) { - - ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel()); - StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); - StoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } - - } // END of caller_str - - if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; } - - if (PI == PE) { - - cur_loc = genLabel(); - L = ConstantInt::get(Int32Ty, cur_loc); - - } else { - - auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); - DenseMap PredMap; - for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { - - BasicBlock *PBB = *PI; - auto It = PredMap.insert({PBB, genLabel()}); - unsigned Label = It.first->second; - // cur_loc = Label; - PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB); - - } - - L = PN; - - } - - /* Load prev_loc */ - LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); - PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *PrevLocTrans; - -#ifdef AFL_HAVE_VECTOR_INTRINSICS - /* "For efficiency, we propose to hash the tuple as a key into the - hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where - prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */ - - if (ngram_size) - PrevLocTrans = - IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty()); - else -#endif - PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); - - if (caller_str) - PrevLocTrans = - IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCaller), Int32Ty); - - /* Load SHM pointer */ - LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); - MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *MapPtrIdx; -#ifdef AFL_HAVE_VECTOR_INTRINSICS - if (ngram_size) - MapPtrIdx = IRB.CreateGEP( - MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty)); - else -#endif - MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L)); - - /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - Value *Incr = IRB.CreateAdd(Counter, One); - -#if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) // with llvm 9 we make this the default as the bug in llvm is - // then fixed -#else - if (!skip_nozero) -#endif - { - - /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to - * 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter - */ - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); - - } - - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - if (caller_str && has_calls) { - - // in CALLER mode we have to restore the original context for the - // caller - she might be calling other functions which need the - // correct CALLER - Instruction *Inst = BB.getTerminator(); - if (isa(Inst) || isa(Inst)) { - - IRBuilder<> Post_IRB(Inst); - StoreInst * RestoreCtx = - Post_IRB.CreateStore(PrevCaller, AFLContext); - RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } - - } - - total_instr++; - - } - - } - - if (!be_quiet) { - - char modeline[100]; - snprintf(modeline, sizeof(modeline), "%s%s%s%s%s", - getenv("AFL_HARDEN") ? "hardened" : "non-hardened", - getenv("AFL_USE_ASAN") ? ", ASAN" : "", - getenv("AFL_USE_MSAN") ? ", MSAN" : "", - getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", - getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - - OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr, - total_rs, total_hs, modeline); - - } - - return false; - - } - -}; // end of struct InsTrim - -} // end of anonymous namespace - -char InsTrim::ID = 0; - -static void registerAFLPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { - - PM.add(new InsTrim()); - -} - -static RegisterStandardPasses RegisterAFLPass( - PassManagerBuilder::EP_OptimizerLast, registerAFLPass); - -static RegisterStandardPasses RegisterAFLPass0( - PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); - diff --git a/instrumentation/MarkNodes.cc b/instrumentation/MarkNodes.cc deleted file mode 100644 index b77466d9..00000000 --- a/instrumentation/MarkNodes.cc +++ /dev/null @@ -1,481 +0,0 @@ -#include -#include -#include -#include -#include - -#include "llvm/Config/llvm-config.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 -typedef long double max_align_t; -#endif - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/BasicBlock.h" -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) - #include "llvm/IR/CFG.h" -#else - #include "llvm/Support/CFG.h" -#endif -#include "llvm/IR/Constants.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -DenseMap LMap; -std::vector Blocks; -std::set Marked, Markabove; -std::vector > Succs, Preds; - -void reset() { - - LMap.clear(); - Blocks.clear(); - Marked.clear(); - Markabove.clear(); - -} - -uint32_t start_point; - -void labelEachBlock(Function *F) { - - // Fake single endpoint; - LMap[NULL] = Blocks.size(); - Blocks.push_back(NULL); - - // Assign the unique LabelID to each block; - for (auto I = F->begin(), E = F->end(); I != E; ++I) { - - BasicBlock *BB = &*I; - LMap[BB] = Blocks.size(); - Blocks.push_back(BB); - - } - - start_point = LMap[&F->getEntryBlock()]; - -} - -void buildCFG(Function *F) { - - Succs.resize(Blocks.size()); - Preds.resize(Blocks.size()); - for (size_t i = 0; i < Succs.size(); i++) { - - Succs[i].clear(); - Preds[i].clear(); - - } - - for (auto S = F->begin(), E = F->end(); S != E; ++S) { - - BasicBlock *BB = &*S; - uint32_t MyID = LMap[BB]; - - for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { - - Succs[MyID].push_back(LMap[*I]); - - } - - } - -} - -std::vector > tSuccs; -std::vector tag, indfs; - -void DFStree(size_t now_id) { - - if (tag[now_id]) return; - tag[now_id] = true; - indfs[now_id] = true; - for (auto succ : tSuccs[now_id]) { - - if (tag[succ] and indfs[succ]) { - - Marked.insert(succ); - Markabove.insert(succ); - continue; - - } - - Succs[now_id].push_back(succ); - Preds[succ].push_back(now_id); - DFStree(succ); - - } - - indfs[now_id] = false; - -} - -void turnCFGintoDAG() { - - tSuccs = Succs; - tag.resize(Blocks.size()); - indfs.resize(Blocks.size()); - for (size_t i = 0; i < Blocks.size(); ++i) { - - Succs[i].clear(); - tag[i] = false; - indfs[i] = false; - - } - - DFStree(start_point); - for (size_t i = 0; i < Blocks.size(); ++i) - if (Succs[i].empty()) { - - Succs[i].push_back(0); - Preds[0].push_back(i); - - } - -} - -uint32_t timeStamp; -namespace DominatorTree { - -std::vector > cov; -std::vector dfn, nfd, par, sdom, idom, mom, mn; - -bool Compare(uint32_t u, uint32_t v) { - - return dfn[u] < dfn[v]; - -} - -uint32_t eval(uint32_t u) { - - if (mom[u] == u) return u; - uint32_t res = eval(mom[u]); - if (Compare(sdom[mn[mom[u]]], sdom[mn[u]])) { mn[u] = mn[mom[u]]; } - return mom[u] = res; - -} - -void DFS(uint32_t now) { - - timeStamp += 1; - dfn[now] = timeStamp; - nfd[timeStamp - 1] = now; - for (auto succ : Succs[now]) { - - if (dfn[succ] == 0) { - - par[succ] = now; - DFS(succ); - - } - - } - -} - -void DominatorTree() { - - if (Blocks.empty()) return; - uint32_t s = start_point; - - // Initialization - mn.resize(Blocks.size()); - cov.resize(Blocks.size()); - dfn.resize(Blocks.size()); - nfd.resize(Blocks.size()); - par.resize(Blocks.size()); - mom.resize(Blocks.size()); - sdom.resize(Blocks.size()); - idom.resize(Blocks.size()); - - for (uint32_t i = 0; i < Blocks.size(); i++) { - - dfn[i] = 0; - nfd[i] = Blocks.size(); - cov[i].clear(); - idom[i] = mom[i] = mn[i] = sdom[i] = i; - - } - - timeStamp = 0; - DFS(s); - - for (uint32_t i = Blocks.size() - 1; i >= 1u; i--) { - - uint32_t now = nfd[i]; - if (now == Blocks.size()) { continue; } - for (uint32_t pre : Preds[now]) { - - if (dfn[pre]) { - - eval(pre); - if (Compare(sdom[mn[pre]], sdom[now])) { sdom[now] = sdom[mn[pre]]; } - - } - - } - - cov[sdom[now]].push_back(now); - mom[now] = par[now]; - for (uint32_t x : cov[par[now]]) { - - eval(x); - if (Compare(sdom[mn[x]], par[now])) { - - idom[x] = mn[x]; - - } else { - - idom[x] = par[now]; - - } - - } - - } - - for (uint32_t i = 1; i < Blocks.size(); i += 1) { - - uint32_t now = nfd[i]; - if (now == Blocks.size()) { continue; } - if (idom[now] != sdom[now]) idom[now] = idom[idom[now]]; - - } - -} - -} // namespace DominatorTree - -std::vector Visited, InStack; -std::vector TopoOrder, InDeg; -std::vector > t_Succ, t_Pred; - -void Go(uint32_t now, uint32_t tt) { - - if (now == tt) return; - Visited[now] = InStack[now] = timeStamp; - - for (uint32_t nxt : Succs[now]) { - - if (Visited[nxt] == timeStamp and InStack[nxt] == timeStamp) { - - Marked.insert(nxt); - - } - - t_Succ[now].push_back(nxt); - t_Pred[nxt].push_back(now); - InDeg[nxt] += 1; - if (Visited[nxt] == timeStamp) { continue; } - Go(nxt, tt); - - } - - InStack[now] = 0; - -} - -void TopologicalSort(uint32_t ss, uint32_t tt) { - - timeStamp += 1; - - Go(ss, tt); - - TopoOrder.clear(); - std::queue wait; - wait.push(ss); - while (not wait.empty()) { - - uint32_t now = wait.front(); - wait.pop(); - TopoOrder.push_back(now); - for (uint32_t nxt : t_Succ[now]) { - - InDeg[nxt] -= 1; - if (InDeg[nxt] == 0u) { wait.push(nxt); } - - } - - } - -} - -std::vector > NextMarked; -bool Indistinguish(uint32_t node1, uint32_t node2) { - - if (NextMarked[node1].size() > NextMarked[node2].size()) { - - uint32_t _swap = node1; - node1 = node2; - node2 = _swap; - - } - - for (uint32_t x : NextMarked[node1]) { - - if (NextMarked[node2].find(x) != NextMarked[node2].end()) { return true; } - - } - - return false; - -} - -void MakeUniq(uint32_t now) { - - if (Marked.find(now) == Marked.end()) { - - for (uint32_t pred1 : t_Pred[now]) { - - bool StopFlag = false; - for (uint32_t pred2 : t_Pred[now]) { - - if (pred1 == pred2) continue; - if (Indistinguish(pred1, pred2)) { - - Marked.insert(now); - StopFlag = true; - break; - - } - - } - - if (StopFlag) { break; } - - } - - } - - if (Marked.find(now) != Marked.end()) { - - NextMarked[now].insert(now); - - } else { - - for (uint32_t pred : t_Pred[now]) { - - for (uint32_t x : NextMarked[pred]) { - - NextMarked[now].insert(x); - - } - - } - - } - -} - -bool MarkSubGraph(uint32_t ss, uint32_t tt) { - - TopologicalSort(ss, tt); - if (TopoOrder.empty()) return false; - - for (uint32_t i : TopoOrder) { - - NextMarked[i].clear(); - - } - - NextMarked[TopoOrder[0]].insert(TopoOrder[0]); - for (uint32_t i = 1; i < TopoOrder.size(); i += 1) { - - MakeUniq(TopoOrder[i]); - - } - - // Check if there is an empty path. - if (NextMarked[tt].count(TopoOrder[0]) > 0) return true; - return false; - -} - -void MarkVertice() { - - uint32_t s = start_point; - - InDeg.resize(Blocks.size()); - Visited.resize(Blocks.size()); - InStack.resize(Blocks.size()); - t_Succ.resize(Blocks.size()); - t_Pred.resize(Blocks.size()); - NextMarked.resize(Blocks.size()); - - for (uint32_t i = 0; i < Blocks.size(); i += 1) { - - Visited[i] = InStack[i] = InDeg[i] = 0; - t_Succ[i].clear(); - t_Pred[i].clear(); - - } - - timeStamp = 0; - uint32_t t = 0; - bool emptyPathExists = true; - - while (s != t) { - - emptyPathExists &= MarkSubGraph(DominatorTree::idom[t], t); - t = DominatorTree::idom[t]; - - } - - if (emptyPathExists) { - - // Mark all exit blocks to catch the empty path. - Marked.insert(t_Pred[0].begin(), t_Pred[0].end()); - - } - -} - -// return {marked nodes} -std::pair, std::vector > markNodes( - Function *F) { - - assert(F->size() > 0 && "Function can not be empty"); - - reset(); - labelEachBlock(F); - buildCFG(F); - turnCFGintoDAG(); - DominatorTree::DominatorTree(); - MarkVertice(); - - std::vector Result, ResultAbove; - for (uint32_t x : Markabove) { - - auto it = Marked.find(x); - if (it != Marked.end()) Marked.erase(it); - if (x) ResultAbove.push_back(Blocks[x]); - - } - - for (uint32_t x : Marked) { - - if (x == 0) { - - continue; - - } else { - - Result.push_back(Blocks[x]); - - } - - } - - return {Result, ResultAbove}; - -} - diff --git a/instrumentation/MarkNodes.h b/instrumentation/MarkNodes.h deleted file mode 100644 index 8ddc978d..00000000 --- a/instrumentation/MarkNodes.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __MARK_NODES__ -#define __MARK_NODES__ - -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" -#include - -std::pair, std::vector> -markNodes(llvm::Function *F); - -#endif - diff --git a/instrumentation/README.instrim.md b/instrumentation/README.instrim.md deleted file mode 100644 index 99f6477a..00000000 --- a/instrumentation/README.instrim.md +++ /dev/null @@ -1,30 +0,0 @@ -# InsTrim - -InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing - -## Introduction - -InsTrim is the work of Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang. - -It uses a CFG (call flow graph) and markers to instrument just what -is necessary in the binary (ie less than llvm_mode). As a result the binary is -about 10-15% faster compared to normal llvm_mode however with some coverage loss. -It requires at least llvm version 3.8.0 to build. -If you have LLVM 7+ we recommend PCGUARD instead. - -## Usage - -Set the environment variable `AFL_LLVM_INSTRUMENT=CFG` or `AFL_LLVM_INSTRIM=1` -during compilation of the target. - -There is also special mode which instruments loops in a way so that -afl-fuzz can see which loop path has been selected but not being able to -see how often the loop has been rerun. -This again is a tradeoff for speed for less path information. -To enable this mode set `AFL_LLVM_INSTRIM_LOOPHEAD=1`. - -## Background - -The paper from Chin-Chia Hsu, Che-Yu Wu, Hsu-Chun Hsiao and Shih-Kun Huang: -[InsTrim: Lightweight Instrumentation for Coverage-guided Fuzzing] -(https://www.ndss-symposium.org/wp-content/uploads/2018/07/bar2018_14_Hsu_paper.pdf) diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 2705ce0d..adce6c1d 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -101,8 +101,7 @@ instrumentation by either setting `AFL_CC_COMPILER=LLVM` or pass the parameter The tool honors roughly the same environmental variables as afl-gcc (see [docs/env_variables.md](../docs/env_variables.md)). This includes AFL_USE_ASAN, AFL_HARDEN, and AFL_DONT_OPTIMIZE. However AFL_INST_RATIO is not honored -as it does not serve a good purpose with the more effective PCGUARD, LTO and - instrim CFG analysis. +as it does not serve a good purpose with the more effective PCGUARD analysis. ## 3) Options @@ -116,26 +115,20 @@ For splitting memcmp, strncmp, etc. please see [README.laf-intel.md](README.laf- Then there are different ways of instrumenting the target: -1. There is an optimized instrumentation strategy that uses CFGs and -markers to just instrument what is needed. This increases speed by 10-15% -without any disadvantages -If you want to use this, set AFL_LLVM_INSTRUMENT=CFG or AFL_LLVM_INSTRIM=1 -See [README.instrim.md](README.instrim.md) - -2. An even better instrumentation strategy uses LTO and link time +1. An better instrumentation strategy uses LTO and link time instrumentation. Note that not all targets can compile in this mode, however if it works it is the best option you can use. Simply use afl-clang-lto/afl-clang-lto++ to use this option. See [README.lto.md](README.lto.md) -3. Alternativly you can choose a completely different coverage method: +2. Alternativly you can choose a completely different coverage method: -3a. N-GRAM coverage - which combines the previous visited edges with the +2a. N-GRAM coverage - which combines the previous visited edges with the current one. This explodes the map but on the other hand has proven to be effective for fuzzing. See [README.ngram.md](README.ngram.md) -3b. Context sensitive coverage - which combines the visited edges with an +2b. Context sensitive coverage - which combines the visited edges with an individual caller ID (the function that called the current one) [README.ctx.md](README.ctx.md) diff --git a/instrumentation/README.snapshot.md b/instrumentation/README.snapshot.md index c40a956a..c794c2fd 100644 --- a/instrumentation/README.snapshot.md +++ b/instrumentation/README.snapshot.md @@ -1,5 +1,7 @@ # AFL++ snapshot feature +**NOTE:** the snapshot lkm is currently not supported and needs a maintainer :-) + Snapshotting is a feature that makes a snapshot from a process and then restores its state, which is faster then forking it again. diff --git a/src/afl-cc.c b/src/afl-cc.c index 80fc0742..d134f013 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -66,7 +66,6 @@ enum { INSTRUMENT_CLASSIC = 1, INSTRUMENT_AFL = 1, INSTRUMENT_PCGUARD = 2, - INSTRUMENT_INSTRIM = 3, INSTRUMENT_CFG = 3, INSTRUMENT_LTO = 4, INSTRUMENT_LLVMNATIVE = 5, @@ -639,10 +638,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; - if (instrument_mode == INSTRUMENT_CFG) - cc_params[cc_par_cnt++] = - alloc_printf("%s/libLLVMInsTrim.so", obj_path); - else cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); @@ -1252,8 +1247,7 @@ int main(int argc, char **argv, char **envp) { strcasecmp(ptr, "CFG") == 0) { - compiler_mode = LLVM; - instrument_mode = INSTRUMENT_CFG; + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } else if (strcasecmp(ptr, "AFL") == 0 || @@ -1319,10 +1313,7 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { - if (instrument_mode == 0) - instrument_mode = INSTRUMENT_CFG; - else if (instrument_mode != INSTRUMENT_CFG) - FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together"); + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } @@ -1409,17 +1400,7 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { - if (instrument_mode == INSTRUMENT_LTO) { - - instrument_mode = INSTRUMENT_CFG; - lto_mode = 1; - - } else if (!instrument_mode || instrument_mode == INSTRUMENT_CFG) - - instrument_mode = INSTRUMENT_CFG; - else - FATAL("main instrumentation mode already set with %s", - instrument_mode_string[instrument_mode]); + FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); } @@ -1428,7 +1409,7 @@ int main(int argc, char **argv, char **envp) { lto_mode = 1; if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) instrument_mode = INSTRUMENT_LTO; - else if (instrument_mode != INSTRUMENT_CFG) + else FATAL("main instrumentation mode already set with %s", instrument_mode_string[instrument_mode]); @@ -1642,11 +1623,6 @@ int main(int argc, char **argv, char **envp) { " - CALLER\n" " - CTX\n" " - NGRAM-{2-16}\n" - " INSTRIM no yes module yes yes " - " yes\n" - " - NORMAL\n" - " - CALLER\n" - " - NGRAM-{2-16}\n" " [GCC_PLUGIN] gcc plugin: %s%s\n" " CLASSIC DEFAULT no yes no no no " "yes\n" @@ -1697,9 +1673,7 @@ int main(int argc, char **argv, char **envp) { " CTX: CLASSIC + full callee context " "(instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " - "((instrumentation/README.ngram.md)\n" - " INSTRIM: Dominator tree (for LLVM <= 6.0) " - "(instrumentation/README.instrim.md)\n\n"); + "((instrumentation/README.ngram.md)\n\n"); #undef NATIVE_MSG @@ -1791,19 +1765,15 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, " - "NGRAM-2 ..-16\n" + " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 ..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" - " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" - " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed " - "(option to INSTRIM)\n" " AFL_LLVM_CALLER: use single context sensitive coverage (for " "CLASSIC)\n" " AFL_LLVM_CTX: use full context sensitive coverage (for " "CLASSIC)\n" " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for " - "CLASSIC & INSTRIM)\n"); + "CLASSIC)\n"); #ifdef AFL_CLANG_FLTO if (have_lto) @@ -1951,11 +1921,7 @@ int main(int argc, char **argv, char **envp) { "(requires LLVM 11 or higher)"); #endif - if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG && - instrument_opt_mode & INSTRUMENT_OPT_CTX) - FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX."); - else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) - // we will drop CFG/INSTRIM in the future so do not advertise + if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) FATAL( "CALLER, CTX and NGRAM instrumentation options can only be used with " "the LLVM CLASSIC instrumentation mode."); diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 0a978653..8928ddc9 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -73,8 +73,7 @@ static u32 ld_param_cnt = 1; /* Number of params to 'ld' */ so we exploit this property to keep the code "simple". */ static void edit_params(int argc, char **argv) { - u32 i, instrim = 0, gold_pos = 0, gold_present = 0, rt_present = 0, - rt_lto_present = 0, inst_present = 0; + u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, inst_present = 0; char *ptr; ld_params = ck_alloc(4096 * sizeof(u8 *)); @@ -186,17 +185,16 @@ static void edit_params(int argc, char **argv) { } - if (getenv("AFL_LLVM_INSTRIM")) - instrim = 1; - else if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && - (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0)) - instrim = 1; + if (getenv("AFL_LLVM_INSTRIM") || + ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && + (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) + FATAL("InsTrim was removed because it is not effective. Use a modern LLVM and PCGUARD (which is the default in afl-cc).\n"); if (debug) DEBUGF( - "passthrough=%s instrim=%u, gold_pos=%u, gold_present=%s " + "passthrough=%s, gold_pos=%u, gold_present=%s " "inst_present=%s rt_present=%s rt_lto_present=%s\n", - passthrough ? "true" : "false", instrim, gold_pos, + passthrough ? "true" : "false", gold_pos, gold_present ? "true" : "false", inst_present ? "true" : "false", rt_present ? "true" : "false", rt_lto_present ? "true" : "false"); @@ -230,10 +228,6 @@ static void edit_params(int argc, char **argv) { if (!inst_present) { - if (instrim) - ld_params[ld_param_cnt++] = - alloc_printf("-mllvm=-load=%s/afl-llvm-lto-instrim.so", afl_path); - else ld_params[ld_param_cnt++] = alloc_printf( "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 3ef36b37..eae76643 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -166,27 +166,6 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { } rm -f test-instr.plain - # now for the special llvm_mode things - test -e ../libLLVMInsTrim.so && { - AFL_LLVM_INSTRUMENT=CFG AFL_LLVM_INSTRIM_LOOPHEAD=1 ../afl-clang-fast -o test-instr.instrim ../test-instr.c > /dev/null 2>test.out - test -e test-instr.instrim && { - TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.instrim 2>&1 | grep Captur | awk '{print$3}'` - test "$TUPLES" -gt 1 -a "$TUPLES" -lt 5 && { - $ECHO "$GREEN[+] llvm_mode InsTrim reported $TUPLES instrumented locations which is fine" - } || { - $ECHO "$RED[!] llvm_mode InsTrim instrumentation produces weird numbers: $TUPLES" - CODE=1 - } - rm -f test-instr.instrim test.out - } || { - cat test.out - $ECHO "$RED[!] llvm_mode InsTrim compilation failed" - CODE=1 - } - } || { - $ECHO "$YELLOW[-] llvm_mode InsTrim not compiled, cannot test" - INCOMPLETE=1 - } AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1 test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && { grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && { -- cgit 1.4.1 From c169cb3911b33fbc3974005788ade1c9218ade98 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Mar 2021 20:10:09 +0100 Subject: integrate frida_mode, code-format --- GNUmakefile | 3 +++ docs/Changelog.md | 2 ++ docs/env_variables.md | 5 +++-- frida_mode/Makefile | 32 +++++++++++++++----------------- frida_mode/inc/instrument.h | 7 ------- frida_mode/inc/interceptor.h | 4 ---- frida_mode/inc/prefetch.h | 5 ----- frida_mode/inc/ranges.h | 6 ------ frida_mode/include/instrument.h | 7 +++++++ frida_mode/include/interceptor.h | 4 ++++ frida_mode/include/prefetch.h | 5 +++++ frida_mode/include/ranges.h | 6 ++++++ frida_mode/src/main.c | 8 ++++---- include/forkserver.h | 2 +- qemu_mode/qemuafl | 2 +- src/afl-cc.c | 18 ++++++++++++------ src/afl-common.c | 11 ++++++++++- src/afl-ld-lto.c | 15 +++++++++------ 18 files changed, 82 insertions(+), 60 deletions(-) delete mode 100644 frida_mode/inc/instrument.h delete mode 100644 frida_mode/inc/interceptor.h delete mode 100644 frida_mode/inc/prefetch.h delete mode 100644 frida_mode/inc/ranges.h create mode 100644 frida_mode/include/instrument.h create mode 100644 frida_mode/include/interceptor.h create mode 100644 frida_mode/include/prefetch.h create mode 100644 frida_mode/include/ranges.h (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index ac8fe796..963004bd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -593,6 +593,7 @@ distrib: all $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -603,6 +604,7 @@ binary-only: test_shm test_python ready $(PROGS) $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing + -$(MAKE) -C frida_mode -cd qemu_mode && sh ./build_qemu_support.sh -cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh @@ -648,6 +650,7 @@ install: all $(MANPAGES) @if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi @if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C utils/socket_fuzzing install; fi @if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C utils/argv_fuzzing install; fi + @if [ -f afl-frida-trace.so ]; then install -m 755 afl-frida-trace.so $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/afl_network_proxy/afl-network-server ]; then $(MAKE) -C utils/afl_network_proxy install; fi @if [ -f utils/aflpp_driver/libAFLDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLDriver.a $${DESTDIR}$(HELPER_PATH); fi @if [ -f utils/aflpp_driver/libAFLQemuDriver.a ]; then set -e; install -m 644 utils/aflpp_driver/libAFLQemuDriver.a $${DESTDIR}$(HELPER_PATH); fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 730791da..6ae42b04 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,8 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - frida_mode - new mode that uses frida to fuzz binary-only targets, + thanks to @WorksButNotTested! - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` diff --git a/docs/env_variables.md b/docs/env_variables.md index 572fad01..899b36cc 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -372,7 +372,8 @@ checks or alter some of the more exotic semantics of the tool: may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), `AFL_PATH` will be searched for afl-qemu-trace. + - In QEMU mode (-Q), Unicorn mode (-U) and Frida mode (-O), `AFL_PATH` will + be searched for afl-qemu-trace. - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip prepending `afl-qemu-trace` to your command line. Use this if you wish to use a @@ -605,7 +606,7 @@ optimal values if not already present in the environment: override this by setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. - - By default, `ASAN_OPTIONS` are set to: + - By default, `ASAN_OPTIONS` are set to (among others): ``` abort_on_error=1 detect_leaks=0 diff --git a/frida_mode/Makefile b/frida_mode/Makefile index efae5ebf..822f1c6a 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,41 +1,39 @@ PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)inc/ +INC_DIR:=$(PWD)include/ SRC_DIR:=$(PWD)src/ INCLUDES:=$(wildcard $(INC_DIR)*.h) SOURCES:=$(wildcard $(SRC_DIR)*.c) BUILD_DIR:=$(PWD)build/ -CFLAGS:= $(CFLAGS) \ - -fPIC \ - -D_GNU_SOURCE +CFLAGS+=-fPIC -D_GNU_SOURCE FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" -ARCH:=arm64 -TESTINSTR_BASE:=0x0000aaaaaaaaa000 + ARCH:=arm64 + TESTINSTR_BASE:=0x0000aaaaaaaaa000 endif ifeq "$(ARCH)" "x86_64" -TESTINSTR_BASE:=0x0000555555554000 + TESTINSTR_BASE:=0x0000555555554000 endif ifeq "$(shell uname)" "Darwin" -OS:=macos -AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF -CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations -TEST_LDFLAGS:=-undefined dynamic_lookup + OS:=macos + AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF + CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations + TEST_LDFLAGS:=-undefined dynamic_lookup endif ifeq "$(shell uname)" "Linux" -OS:=linux -AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) -CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor -TEST_LDFLAGS:= + OS:=linux + AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) + CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor + TEST_LDFLAGS:= endif ifndef OS -$(error "Operating system unsupported") + $(error "Operating system unsupported") endif VERSION=14.2.13 @@ -347,4 +345,4 @@ cmin_bash_frida: $(TEST_BIN) -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TEST_BIN) @@ \ No newline at end of file + $(TEST_BIN) @@ diff --git a/frida_mode/inc/instrument.h b/frida_mode/inc/instrument.h deleted file mode 100644 index ff71bed4..00000000 --- a/frida_mode/inc/instrument.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "frida-gum.h" - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); - -void instrument_init(); - diff --git a/frida_mode/inc/interceptor.h b/frida_mode/inc/interceptor.h deleted file mode 100644 index 5ed3cf49..00000000 --- a/frida_mode/inc/interceptor.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "frida-gum.h" - -void intercept(void *address, gpointer replacement, gpointer user_data); - diff --git a/frida_mode/inc/prefetch.h b/frida_mode/inc/prefetch.h deleted file mode 100644 index b7f25a97..00000000 --- a/frida_mode/inc/prefetch.h +++ /dev/null @@ -1,5 +0,0 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); -void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); - diff --git a/frida_mode/inc/ranges.h b/frida_mode/inc/ranges.h deleted file mode 100644 index b9394dbc..00000000 --- a/frida_mode/inc/ranges.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "frida-gum.h" - -void ranges_init(GumStalker *stalker); - -gboolean range_is_excluded(gpointer address); - diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h new file mode 100644 index 00000000..ff71bed4 --- /dev/null +++ b/frida_mode/include/instrument.h @@ -0,0 +1,7 @@ +#include "frida-gum.h" + +void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, + gpointer user_data); + +void instrument_init(); + diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h new file mode 100644 index 00000000..5ed3cf49 --- /dev/null +++ b/frida_mode/include/interceptor.h @@ -0,0 +1,4 @@ +#include "frida-gum.h" + +void intercept(void *address, gpointer replacement, gpointer user_data); + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h new file mode 100644 index 00000000..b7f25a97 --- /dev/null +++ b/frida_mode/include/prefetch.h @@ -0,0 +1,5 @@ +void prefetch_init(); +void prefetch_start(GumStalker *stalker); +void prefetch_write(void *addr); +void prefetch_read(GumStalker *stalker); + diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h new file mode 100644 index 00000000..b9394dbc --- /dev/null +++ b/frida_mode/include/ranges.h @@ -0,0 +1,6 @@ +#include "frida-gum.h" + +void ranges_init(GumStalker *stalker); + +gboolean range_is_excluded(gpointer address); + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 444c9583..7505c2f9 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -22,10 +22,10 @@ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); #else -extern int __libc_start_main(int *(main)(int, char **, char **), int argc, - char **ubp_av, void (*init)(void), - void (*fini)(void), void (*rtld_fini)(void), - void(*stack_end)); +extern int __libc_start_main(int *(main)(int, char **, char **), int argc, + char **ubp_av, void (*init)(void), + void (*fini)(void), void (*rtld_fini)(void), + void(*stack_end)); #endif typedef int *(*main_fn_t)(int argc, char **argv, char **envp); diff --git a/include/forkserver.h b/include/forkserver.h index cc759545..48db94c7 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,7 +77,7 @@ typedef struct afl_forkserver { bool qemu_mode; /* if running in qemu mode or not */ - bool frida_mode; /* if running in frida mode or not */ + bool frida_mode; /* if running in frida mode or not */ bool use_stdin; /* use stdin for sending data */ diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 0fb212da..ddc4a974 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 0fb212daab492411b3e323bc18a3074c1aecfd37 +Subproject commit ddc4a9748d59857753fb33c30a356f354595f36d diff --git a/src/afl-cc.c b/src/afl-cc.c index d134f013..1b4edbb9 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -638,8 +638,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); } @@ -1247,7 +1246,9 @@ int main(int argc, char **argv, char **envp) { strcasecmp(ptr, "CFG") == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } else if (strcasecmp(ptr, "AFL") == 0 || @@ -1313,7 +1314,9 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") || getenv("INSTRIM_LIB")) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD " + "(default in afl-cc).\n"); } @@ -1400,7 +1403,9 @@ int main(int argc, char **argv, char **envp) { if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { - FATAL("InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD (default in afl-cc).\n"); + FATAL( + "InsTrim instrumentation was removed. Use a modern LLVM and " + "PCGUARD (default in afl-cc).\n"); } @@ -1765,7 +1770,8 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 ..-16\n" + " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 " + "..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" " AFL_LLVM_CALLER: use single context sensitive coverage (for " diff --git a/src/afl-common.c b/src/afl-common.c index 087aa113..0fb1462e 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -336,7 +336,16 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) { } - target_path = alloc_printf("%s/%s", BIN_PATH, fname); + if (perm == X_OK) { + + target_path = alloc_printf("%s/%s", BIN_PATH, fname); + + } else { + + target_path = alloc_printf("%s/%s", AFL_PATH, fname); + + } + if (!access(target_path, perm)) { return target_path; diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 8928ddc9..d0113af9 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -73,7 +73,8 @@ static u32 ld_param_cnt = 1; /* Number of params to 'ld' */ so we exploit this property to keep the code "simple". */ static void edit_params(int argc, char **argv) { - u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, inst_present = 0; + u32 i, gold_pos = 0, gold_present = 0, rt_present = 0, rt_lto_present = 0, + inst_present = 0; char *ptr; ld_params = ck_alloc(4096 * sizeof(u8 *)); @@ -185,10 +186,12 @@ static void edit_params(int argc, char **argv) { } - if (getenv("AFL_LLVM_INSTRIM") || + if (getenv("AFL_LLVM_INSTRIM") || ((ptr = getenv("AFL_LLVM_INSTRUMENT")) && - (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) - FATAL("InsTrim was removed because it is not effective. Use a modern LLVM and PCGUARD (which is the default in afl-cc).\n"); + (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))) + FATAL( + "InsTrim was removed because it is not effective. Use a modern LLVM " + "and PCGUARD (which is the default in afl-cc).\n"); if (debug) DEBUGF( @@ -228,8 +231,8 @@ static void edit_params(int argc, char **argv) { if (!inst_present) { - ld_params[ld_param_cnt++] = alloc_printf( - "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); + ld_params[ld_param_cnt++] = alloc_printf( + "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path); } -- cgit 1.4.1 From 2c5844f6657861cfc881adf2f38aa5d3da3ccf9d Mon Sep 17 00:00:00 2001 From: Yong-Hao Zou Date: Fri, 26 Mar 2021 15:41:19 +0800 Subject: Update custom_mutators.md --- docs/custom_mutators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 61d711e4..62e01f83 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -89,10 +89,10 @@ def queue_get(filename): def queue_new_entry(filename_new_queue, filename_orig_queue): pass -``` def introspection(): return string +``` ### Custom Mutation -- cgit 1.4.1 From 7ca51fab19adfcda211282d4a1134eada7b60d2b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Mar 2021 12:53:09 +0100 Subject: ensure one fuzzer sync per cycle, cycle introspection --- docs/Changelog.md | 1 + include/afl-fuzz.h | 1 + src/afl-fuzz-run.c | 1 + src/afl-fuzz.c | 22 +++++++++++++++------- 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6ae42b04..91d1a8cc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,6 +18,7 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - ensure one fuzzer sync per cycle - afl-cc: - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 046b0177..40a7fc85 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -572,6 +572,7 @@ typedef struct afl_state { blocks_eff_select, /* Blocks selected as fuzzable */ start_time, /* Unix start time (ms) */ last_sync_time, /* Time of last sync */ + last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ last_hang_time; /* Time for most recent hang (ms) */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 83133dad..832f17bb 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -712,6 +712,7 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); afl->last_sync_time = get_cur_time(); + afl->last_sync_cycle = afl->queue_cycle; } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a7edb924..9688c84f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1867,6 +1867,14 @@ int main(int argc, char **argv_orig, char **envp) { runs_in_current_cycle > afl->queued_paths) || (afl->old_seed_selection && !afl->queue_cur))) { + if (unlikely((afl->last_sync_cycle < afl->queue_cycle || + (!afl->queue_cycle && afl->afl_env.afl_import_first)) && + afl->sync_id)) { + + sync_fuzzers(afl); + + } + ++afl->queue_cycle; runs_in_current_cycle = (u32)-1; afl->cur_skipped_paths = 0; @@ -1980,6 +1988,13 @@ int main(int argc, char **argv_orig, char **envp) { } + #ifdef INTROSPECTION + fprintf(afl->introspection_file, + "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n", + afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc, + afl->queued_paths); + #endif + if (afl->cycle_schedules) { /* we cannot mix non-AFLfast schedules with others */ @@ -2031,13 +2046,6 @@ int main(int argc, char **argv_orig, char **envp) { prev_queued = afl->queued_paths; - if (afl->sync_id && afl->queue_cycle == 1 && - afl->afl_env.afl_import_first) { - - sync_fuzzers(afl); - - } - } ++runs_in_current_cycle; -- cgit 1.4.1 From 920e9402a4d6101bbbed2ef7584d85a3c3de0eaa Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 2 Apr 2021 22:23:11 +0000 Subject: Add support for standalone leak-sanitizer, introducting the environment variable AFL_USE_LSAN. AFL_USE_LSAN introduces the macro __AFL_CHECK_LEAK() which will check for a memory leak when the macro is run. This is especially helpful when using __AFL_LOOP(). If __AFL_LEAK_CHECK() is not used when AFL_USE_LSAN=1 is set, the leak checker will run when the program exits. --- GNUmakefile | 4 ++-- README.md | 2 +- docs/env_variables.md | 20 ++++++++++++++++---- docs/notes_for_asan.md | 7 +++++++ include/config.h | 4 ++++ include/envs.h | 1 + src/afl-analyze.c | 19 +++++++++++++++++++ src/afl-as.c | 7 ++++--- src/afl-cc.c | 16 ++++++++++++++-- src/afl-forkserver.c | 17 +++++++++++++---- src/afl-fuzz-init.c | 17 ++++++++++++++++- src/afl-showmap.c | 4 ++++ src/afl-tmin.c | 18 ++++++++++++++++++ test/test-pre.sh | 1 + 14 files changed, 120 insertions(+), 17 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index f885f998..a6314a8b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -517,7 +517,7 @@ code-format: ifndef AFL_NO_X86 test_build: afl-cc afl-gcc afl-as afl-showmap @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." - @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) + @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @@ -525,7 +525,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap @echo @echo "[+] All right, the instrumentation of afl-cc seems to be working!" # @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." -# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) +# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr # @rm -f test-instr diff --git a/README.md b/README.md index 2528e1d1..41d55e9c 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; - export AFL_USE_CFISAN=1 ; ` + export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN`) * one should fuzz the target with CMPLOG/redqueen (see above) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV diff --git a/docs/env_variables.md b/docs/env_variables.md index c6ad0aa4..682ab7f1 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: overridden. - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - compiler supports that. Note that fuzzing with ASAN is mildly challenging + compiler supports itt. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the @@ -64,6 +64,13 @@ make fairly broad use of environmental variables instead: there is the Control Flow Integrity sanitizer that can be activated by `AFL_USE_CFISAN=1`) + - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided + that your compiler supports it. To perform a leak check within your + program at a certain point (such as at the end of an __AFL_LOOP, + you can run the macro __AFL_CHECK_LEAK(); which will cause + an abort if any memory is leaked (you can combine this with the + LSAN_OPTIONS=suppressions option to supress some known leaks). + - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries in your `$PATH`. @@ -628,7 +635,12 @@ optimal values if not already present in the environment: msan_track_origins=0 allocator_may_return_null=1 ``` - Be sure to include the first one when customizing anything, since some - MSAN versions don't call `abort()` on error, and we need a way to detect - faults. + - Similarly, the default `LSAN_OPTIONS` are set to: +``` + exit_code=86 + fast_unwind_on_malloc=0 +```` + Be sure to include the first ones for LSAN and MSAN when customizing + anything, since some MSAN and LSAN versions don't call `abort()` on + error, and we need a way to detect faults. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 2b3bc028..26f34fad 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that. (You can also use AFL_USE_MSAN=1 to enable MSAN instead.) +When compiling with AFL_USE_LSAN, the leak sanitizer will normally run +when the program exits. In order to utilize this check at different times, +such as at the end of a loop, you may use the macro __AFL_CHECK_LEAK();. +This macro will report a crash in afl-fuzz if any memory is left leaking +at this stage. You can also use LSAN_OPTIONS and a supressions file +for more fine-tuned checking, however make sure you keep exitcode=23. + NOTE: if you run several secondary instances, only one should run the target compiled with ASAN (and UBSAN, CFISAN), the others should run the target with no sanitizers compiled in. diff --git a/include/config.h b/include/config.h index 29225f6b..6490a5fe 100644 --- a/include/config.h +++ b/include/config.h @@ -393,6 +393,10 @@ #define MSAN_ERROR 86 +/* Distinctive exit code used to indicate LSAN trip condition: */ + +#define LSAN_ERROR 23 + /* Designated file descriptors for forkserver commands (the application will use FORKSRV_FD and FORKSRV_FD + 1): */ diff --git a/include/envs.h b/include/envs.h index 2ce50be7..d1856c50 100644 --- a/include/envs.h +++ b/include/envs.h @@ -172,6 +172,7 @@ static char *afl_environment_variables[] = { "AFL_USE_TRACE_PC", "AFL_USE_UBSAN", "AFL_USE_CFISAN", + "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 86b0f7e9..90305714 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -781,6 +781,19 @@ static void set_up_environment(void) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -818,6 +831,12 @@ static void set_up_environment(void) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(MSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + + if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-as.c b/src/afl-as.c index 7de267a3..dfae44f2 100644 --- a/src/afl-as.c +++ b/src/afl-as.c @@ -517,11 +517,12 @@ static void add_instrumentation(void) { } else { char modeline[100]; - snprintf(modeline, sizeof(modeline), "%s%s%s%s", + snprintf(modeline, sizeof(modeline), "%s%s%s%s%s", getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_USE_ASAN") ? ", ASAN" : "", getenv("AFL_USE_MSAN") ? ", MSAN" : "", - getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); + getenv("AFL_USE_UBSAN") ? ", UBSAN" : "", + getenv("AFL_USE_LSAN") ? ", LSAN" : ""); OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines, use_64bit ? "64" : "32", modeline, inst_ratio); @@ -585,7 +586,7 @@ int main(int argc, char **argv) { "AFL_QUIET: suppress verbose output\n" "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n" "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n" - "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN:\n" + "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n" " used in the instrumentation summary message\n", argv[0]); diff --git a/src/afl-cc.c b/src/afl-cc.c index 5251465b..e0478503 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) have_instr_list = 1; - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) + if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory"))) asan_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; @@ -817,6 +817,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; + } + if (getenv("AFL_USE_CFISAN")) { if (!lto_mode) { @@ -914,6 +918,13 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; + } + + cc_params[cc_par_cnt++] = + "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " "1;"; @@ -1740,7 +1751,8 @@ int main(int argc, char **argv, char **envp) { " AFL_USE_ASAN: activate address sanitizer\n" " AFL_USE_CFISAN: activate control flow sanitizer\n" " AFL_USE_MSAN: activate memory sanitizer\n" - " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"); + " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" + " AFL_USE_LSAN: activate leak-checker sanitizer\n"); if (have_gcc_plugin) SAYF( diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 68995388..fa89713a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -483,7 +483,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); } - /* Set sane defaults for ASAN if nothing else specified. */ + /* Set sane defaults for ASAN if nothing else is specified. */ if (!getenv("ASAN_OPTIONS")) setenv("ASAN_OPTIONS", @@ -500,7 +500,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); - /* Set sane defaults for UBSAN if nothing else specified. */ + /* Set sane defaults for UBSAN if nothing else is specified. */ if (!getenv("UBSAN_OPTIONS")) setenv("UBSAN_OPTIONS", @@ -538,6 +538,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "handle_sigill=0", 1); + /* LSAN, too, does not support abort_on_error=1. */ + + if (!getenv("LSAN_OPTIONS")) + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 1); + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -1210,8 +1218,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (unlikely( /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || - /* special handling for msan */ - (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + /* special handling for msan and lsan */ + (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 82c1799e..24f5c5b5 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2466,6 +2466,20 @@ void check_asan_opts(afl_state_t *afl) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + + } /* Handle stop signal (Ctrl-C, etc). */ @@ -2711,7 +2725,8 @@ void check_binary(afl_state_t *afl, u8 *fname) { } if (memmem(f_data, f_len, "__asan_init", 11) || - memmem(f_data, f_len, "__msan_init", 11)) { + memmem(f_data, f_len, "__msan_init", 11) || + memmem(f_data, f_len, "__lsan_init", 11)) { afl->fsrv.uses_asan = 1; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 7bf5a9c7..bf076683 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -570,6 +570,10 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); setenv("UBSAN_OPTIONS", "halt_on_error=1:" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 7ef8b9bf..a2741a07 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -712,6 +712,19 @@ static void set_up_environment(afl_forkserver_t *fsrv) { } + x = get_afl_env("LSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + + FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( + LSAN_ERROR) " - please fix!"); + + } + + } + setenv("ASAN_OPTIONS", "abort_on_error=1:" "detect_leaks=0:" @@ -749,6 +762,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", + "exitcode=" STRINGIFY(LSAN_ERROR) ":" + "fast_unwind_on_malloc=0", + 0); + if (get_afl_env("AFL_PRELOAD")) { if (fsrv->qemu_mode) { diff --git a/test/test-pre.sh b/test/test-pre.sh index 85ac320b..174f2f7f 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -71,6 +71,7 @@ unset AFL_HARDEN unset AFL_USE_ASAN unset AFL_USE_MSAN unset AFL_USE_UBSAN +unset AFL_USE_LSAN unset AFL_TMPDIR unset AFL_CC unset AFL_PRELOAD -- cgit 1.4.1 From 6514e33ab6733dd4e7ae0d3eeec83db06b3f451f Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Fri, 2 Apr 2021 22:32:38 +0000 Subject: Replace __AFL_CHECK_LEAK with __AFL_LEAK_CHECK to be more proper. Fix spelling mistakes. Correctly call LSAN_ERROR not MSAN_ERROR. --- docs/env_variables.md | 8 ++++---- docs/notes_for_asan.md | 2 +- src/afl-analyze.c | 2 +- src/afl-cc.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index 682ab7f1..85c2efd7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead: overridden. - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - compiler supports itt. Note that fuzzing with ASAN is mildly challenging + compiler supports it. Note that fuzzing with ASAN is mildly challenging - see [notes_for_asan.md](notes_for_asan.md). (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the @@ -66,8 +66,8 @@ make fairly broad use of environmental variables instead: - Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided that your compiler supports it. To perform a leak check within your - program at a certain point (such as at the end of an __AFL_LOOP, - you can run the macro __AFL_CHECK_LEAK(); which will cause + program at a certain point (such as at the end of an __AFL_LOOP), + you can run the macro __AFL_LEAK_CHECK(); which will cause an abort if any memory is leaked (you can combine this with the LSAN_OPTIONS=suppressions option to supress some known leaks). @@ -637,7 +637,7 @@ optimal values if not already present in the environment: ``` - Similarly, the default `LSAN_OPTIONS` are set to: ``` - exit_code=86 + exit_code=23 fast_unwind_on_malloc=0 ```` Be sure to include the first ones for LSAN and MSAN when customizing diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md index 26f34fad..f55aeaf2 100644 --- a/docs/notes_for_asan.md +++ b/docs/notes_for_asan.md @@ -30,7 +30,7 @@ Note that ASAN is incompatible with -static, so be mindful of that. When compiling with AFL_USE_LSAN, the leak sanitizer will normally run when the program exits. In order to utilize this check at different times, -such as at the end of a loop, you may use the macro __AFL_CHECK_LEAK();. +such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();. This macro will report a crash in afl-fuzz if any memory is left leaking at this stage. You can also use LSAN_OPTIONS and a supressions file for more fine-tuned checking, however make sure you keep exitcode=23. diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 90305714..f961f13a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -832,7 +832,7 @@ static void set_up_environment(void) { "handle_sigill=0", 0); setenv("LSAN_OPTIONS", - "exitcode=" STRINGIFY(MSAN_ERROR) ":" + "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index e0478503..975b28d1 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -923,7 +923,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } cc_params[cc_par_cnt++] = - "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()"; + "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " -- cgit 1.4.1 From afc4da47f78a24d5e441e3815e5b322d1b27fd56 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sat, 3 Apr 2021 14:50:35 +0000 Subject: Fix typos, Use symbolize=0 for LSAN, Remove syntactic sugar. --- README.md | 2 +- docs/env_variables.md | 3 ++- src/afl-analyze.c | 8 ++++---- src/afl-cc.c | 2 +- src/afl-forkserver.c | 3 ++- src/afl-fuzz-init.c | 5 ++--- src/afl-showmap.c | 4 +++- src/afl-tmin.c | 3 ++- 8 files changed, 17 insertions(+), 13 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 41d55e9c..4d3f8aa9 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same For every secondary fuzzer there should be a variation, e.g.: * one should fuzz the target that was compiled differently: with sanitizers activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; - export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN`) + export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`) * one should fuzz the target with CMPLOG/redqueen (see above) * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV diff --git a/docs/env_variables.md b/docs/env_variables.md index 85c2efd7..5f9233d7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -639,7 +639,8 @@ optimal values if not already present in the environment: ``` exit_code=23 fast_unwind_on_malloc=0 -```` + symbolize=0 +``` Be sure to include the first ones for LSAN and MSAN when customizing anything, since some MSAN and LSAN versions don't call `abort()` on error, and we need a way to detect faults. diff --git a/src/afl-analyze.c b/src/afl-analyze.c index f961f13a..38a40556 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -785,10 +785,9 @@ static void set_up_environment(void) { if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( - LSAN_ERROR) " - please fix!"); + FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); } @@ -833,7 +832,8 @@ static void set_up_environment(void) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index 975b28d1..650e4e43 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) have_instr_list = 1; - if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory"))) + if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) asan_set = 1; if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index fa89713a..f102b73b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -543,7 +543,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!getenv("LSAN_OPTIONS")) setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 1); fsrv->init_child_func(fsrv, argv); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 24f5c5b5..6f663021 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2470,10 +2470,9 @@ void check_asan_opts(afl_state_t *afl) { if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) { + if (!strstr(x, "symbolize=0")) { - FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY( - LSAN_ERROR) " - please fix!"); + FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index bf076683..2b7d200b 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -570,9 +570,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "handle_sigfpe=0:" "handle_sigill=0", 0); + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); setenv("UBSAN_OPTIONS", diff --git a/src/afl-tmin.c b/src/afl-tmin.c index a2741a07..c257b67c 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -764,7 +764,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" - "fast_unwind_on_malloc=0", + "fast_unwind_on_malloc=0:" + "symbolize=0", 0); if (get_afl_env("AFL_PRELOAD")) { -- cgit 1.4.1 From 99819cf5d1cbc262810f26098a5796c9d1262bc5 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sun, 4 Apr 2021 12:45:52 +0000 Subject: Move definition of __AFL_LEAK_CHECK inside ifguards, use LSAN_OPTIONS=print_suppressions=0 --- docs/env_variables.md | 1 + src/afl-analyze.c | 3 ++- src/afl-cc.c | 10 +++------- src/afl-forkserver.c | 3 ++- src/afl-showmap.c | 3 ++- src/afl-tmin.c | 3 ++- 6 files changed, 12 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index 5f9233d7..83bc487f 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -640,6 +640,7 @@ optimal values if not already present in the environment: exit_code=23 fast_unwind_on_malloc=0 symbolize=0 + print_suppressions=0 ``` Be sure to include the first ones for LSAN and MSAN when customizing anything, since some MSAN and LSAN versions don't call `abort()` on diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 38a40556..f4436980 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -833,7 +833,8 @@ static void set_up_environment(void) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); diff --git a/src/afl-cc.c b/src/afl-cc.c index 650e4e43..e2dd06e2 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -819,6 +819,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (getenv("AFL_USE_LSAN")) { cc_params[cc_par_cnt++] = "-fsanitize=leak"; + cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; + cc_params[cc_par_cnt++] = + "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; } if (getenv("AFL_USE_CFISAN")) { @@ -918,13 +921,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (getenv("AFL_USE_LSAN")) { - cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; - } - - cc_params[cc_par_cnt++] = - "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; - cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = " "1;"; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index f102b73b..ac7a1600 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -544,7 +544,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 1); fsrv->init_child_func(fsrv, argv); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 2b7d200b..df91a4c2 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -574,7 +574,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); setenv("UBSAN_OPTIONS", diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 3a196e2e..eb5e0dcf 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -764,7 +764,8 @@ static void set_up_environment(afl_forkserver_t *fsrv) { setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" - "symbolize=0", + "symbolize=0:" + "print_suppressions=0", 0); if (get_afl_env("AFL_PRELOAD")) { -- cgit 1.4.1 From 3c846859eef4d17d2587ea28db83c680b51723a7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Apr 2021 20:05:02 +0200 Subject: cleanup --- GNUmakefile | 38 ++++++++++++---------- GNUmakefile.gcc_plugin | 12 ++++--- GNUmakefile.llvm | 8 +++-- docs/Changelog.md | 3 ++ include/android-ashmem.h | 16 +++++---- instrumentation/afl-llvm-lto-instrumentation.so.cc | 2 +- src/afl-analyze.c | 3 +- src/afl-cc.c | 5 +-- src/afl-forkserver.c | 7 ++-- src/afl-fuzz-init.c | 1 - src/afl-tmin.c | 2 +- 11 files changed, 55 insertions(+), 42 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index fdbcd542..d5fb570d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -36,6 +36,11 @@ SH_PROGS = afl-plot afl-cmin afl-cmin.bash afl-whatsup afl-system-config MANPAGES=$(foreach p, $(PROGS) $(SH_PROGS), $(p).8) afl-as.8 ASAN_OPTIONS=detect_leaks=0 +SYS = $(shell uname -s) +ARCH = $(shell uname -m) + +$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH)) + ifdef NO_SPLICING override CFLAGS += -DNO_SPLICING endif @@ -82,7 +87,7 @@ endif # endif #endif -ifneq "$(shell uname)" "Darwin" +ifneq "$(SYS)" "Darwin" #ifeq "$(HAVE_MARCHNATIVE)" "1" # SPECIAL_PERFORMANCE += -march=native #endif @@ -92,7 +97,7 @@ ifneq "$(shell uname)" "Darwin" endif endif -ifeq "$(shell uname)" "SunOS" +ifeq "$(SYS)" "SunOS" CFLAGS_OPT += -Wno-format-truncation LDFLAGS = -lkstat -lrt endif @@ -119,11 +124,10 @@ ifdef INTROSPECTION CFLAGS_OPT += -DINTROSPECTION=1 endif - -ifneq "$(shell uname -m)" "x86_64" - ifneq "$(patsubst i%86,i386,$(shell uname -m))" "i386" - ifneq "$(shell uname -m)" "amd64" - ifneq "$(shell uname -m)" "i86pc" +ifneq "$(ARCH)" "x86_64" + ifneq "$(patsubst i%86,i386,$(ARCH))" "i386" + ifneq "$(ARCH)" "amd64" + ifneq "$(ARCH)" "i86pc" AFL_NO_X86=1 endif endif @@ -141,27 +145,27 @@ override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpoi -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" -ifeq "$(shell uname -s)" "FreeBSD" +ifeq "$(SYS)" "FreeBSD" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" override CFLAGS += -I /usr/local/include/ LDFLAGS += -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" override CFLAGS += -I /usr/local/include/ -mno-retpoline LDFLAGS += -Wl,-z,notext -L /usr/local/lib/ endif -ifeq "$(shell uname -s)" "NetBSD" +ifeq "$(SYS)" "NetBSD" override CFLAGS += -I /usr/pkg/include/ LDFLAGS += -L /usr/pkg/lib/ endif -ifeq "$(shell uname -s)" "Haiku" +ifeq "$(SYS)" "Haiku" SHMAT_OK=0 override CFLAGS += -DUSEMMAP=1 -Wno-error=format -fPIC LDFLAGS += -Wno-deprecated-declarations -lgnu @@ -236,24 +240,24 @@ else BUILD_DATE ?= $(shell date "+%Y-%m-%d") endif -ifneq "$(filter Linux GNU%,$(shell uname))" "" +ifneq "$(filter Linux GNU%,$(SYS))" "" ifndef DEBUG override CFLAGS += -D_FORTIFY_SOURCE=2 endif LDFLAGS += -ldl -lrt -lm endif -ifneq "$(findstring FreeBSD, $(shell uname))" "" +ifneq "$(findstring FreeBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring NetBSD, $(shell uname))" "" +ifneq "$(findstring NetBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif -ifneq "$(findstring OpenBSD, $(shell uname))" "" +ifneq "$(findstring OpenBSD, $(ARCH))" "" override CFLAGS += -pthread LDFLAGS += -lpthread endif @@ -485,7 +489,7 @@ unit_clean: @rm -f ./test/unittests/unit_preallocable ./test/unittests/unit_list ./test/unittests/unit_maybe_alloc test/unittests/*.o .PHONY: unit -ifneq "$(shell uname)" "Darwin" +ifneq "$(ARCH)" "Darwin" unit: unit_maybe_alloc unit_preallocable unit_list unit_clean unit_rand unit_hash else unit: diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index aa93c688..b0f90f1b 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -41,6 +41,8 @@ CXXEFLAGS := $(CXXFLAGS) -Wall -std=c++11 CC ?= gcc CXX ?= g++ +SYS = $(shell uname -s) + ifeq "clang" "$(CC)" CC = gcc CXX = g++ @@ -75,25 +77,25 @@ ifeq "$(TEST_MMAP)" "1" override CFLAGS_SAFE += -DUSEMMAP=1 endif -ifneq "$(shell uname -s)" "Haiku" -ifneq "$(shell uname -s)" "OpenBSD" +ifneq "$(SYS)" "Haiku" +ifneq "$(SYS)" "OpenBSD" LDFLAGS += -lrt endif else CFLAGS_SAFE += -DUSEMMAP=1 endif -ifeq "$(shell uname -s)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CC = egcc CXX = eg++ PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "DragonFly" +ifeq "$(SYS)" "DragonFly" PLUGIN_FLAGS += -I/usr/local/include endif -ifeq "$(shell uname -s)" "SunOS" +ifeq "$(SYS)" "SunOS" PLUGIN_FLAGS += -I/usr/include/gmp endif diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 4b5ac520..61c17e92 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -30,7 +30,9 @@ BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/nul VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2) -ifeq "$(shell uname)" "OpenBSD" +SYS = $(shell uname -s) + +ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" @@ -275,13 +277,13 @@ CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS) # User teor2345 reports that this is required to make things work on MacOS X. -ifeq "$(shell uname)" "Darwin" +ifeq "$(SYS)" "Darwin" CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress else CLANG_CPPFL += -Wl,-znodelete endif -ifeq "$(shell uname)" "OpenBSD" +ifeq "$(SYS)" "OpenBSD" CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so CLANG_CPPFL += -mno-retpoline CFLAGS += -mno-retpoline diff --git a/docs/Changelog.md b/docs/Changelog.md index 91d1a8cc..24877f9a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,8 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, thanks to @WorksButNotTested! + - create a fuzzing dictionary with the help of CodeQL thanks to + @microsvuln! see utils/autodict_ql - afl-fuzz: - added patch by @realmadsci to support @@ as part of command line options, e.g. `afl-fuzz ... -- ./target --infile=@@` @@ -20,6 +22,7 @@ sending a mail to . - default cmplog level (-l) is now 2, better efficiency. - ensure one fuzzer sync per cycle - afl-cc: + - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD ### Version ++3.12c (release) diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 44fe556a..1bfd3220 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -13,12 +13,14 @@ #include #define ASHMEM_DEVICE "/dev/ashmem" -int shmdt(const void* address) { -#if defined(SYS_shmdt) +int shmdt(const void *address) { + + #if defined(SYS_shmdt) return syscall(SYS_shmdt, address); -#else + #else return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); -#endif + #endif + } int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { @@ -26,7 +28,7 @@ int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { int ret = 0; if (__cmd == IPC_RMID) { - int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); struct ashmem_pin pin = {0, length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); @@ -77,6 +79,6 @@ void *shmat(int __shmid, const void *__shmaddr, int __shmflg) { } - #endif /* !_ANDROID_ASHMEM_H */ -#endif /* !__ANDROID__ */ + #endif /* !_ANDROID_ASHMEM_H */ +#endif /* !__ANDROID__ */ diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 50306224..6eb19060 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -176,7 +176,7 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (debug) { fprintf(stderr, "map address is 0x%lx\n", map_addr); } + if (debug) { fprintf(stderr, "map address is 0x%llx\n", map_addr); } /* Get/set the globals for the SHM region. */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 7d7519fa..aabdbf1a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -833,14 +833,13 @@ static void set_up_environment(char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" "print_suppressions=0", 0); - if (get_afl_env("AFL_PRELOAD")) { if (qemu_mode) { diff --git a/src/afl-cc.c b/src/afl-cc.c index d4c0a6b7..3af31b3c 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -820,10 +820,11 @@ static void edit_params(u32 argc, char **argv, char **envp) { } if (getenv("AFL_USE_LSAN")) { + cc_params[cc_par_cnt++] = "-fsanitize=leak"; cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h"; - cc_params[cc_par_cnt++] = - "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()"; + } if (getenv("AFL_USE_CFISAN")) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index cd04e23d..2c502621 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -560,7 +560,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* LSAN, too, does not support abort_on_error=1. */ if (!getenv("LSAN_OPTIONS")) - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" @@ -1314,8 +1314,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || /* special handling for msan and lsan */ - (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || - WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || + (fsrv->uses_asan && + (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 48f3289d..e505abd4 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2502,7 +2502,6 @@ void check_asan_opts(afl_state_t *afl) { } - } /* Handle stop signal (Ctrl-C, etc). */ diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 6aad748c..6656712a 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -763,7 +763,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { "handle_sigfpe=0:" "handle_sigill=0", 0); - setenv("LSAN_OPTIONS", + setenv("LSAN_OPTIONS", "exitcode=" STRINGIFY(LSAN_ERROR) ":" "fast_unwind_on_malloc=0:" "symbolize=0:" -- cgit 1.4.1 From 019b26de58a4e7eb4b95aab6425beba4efb853f4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 Apr 2021 11:19:40 +0200 Subject: fix afl_custom_queue_new_entry when syncing --- docs/Changelog.md | 3 +++ instrumentation/afl-llvm-lto-instrumentation.so.cc | 2 +- src/afl-fuzz-queue.c | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 24877f9a..072320dc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -21,9 +21,12 @@ sending a mail to . AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. - ensure one fuzzer sync per cycle + - fix afl_custom_queue_new_entry original file name when syncing + from fuzzers - afl-cc: - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD + - Removed automatic linking with -lc++ for LTO mode ### Version ++3.12c (release) - afl-fuzz: diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 6eb19060..f6cdbe9e 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -92,7 +92,7 @@ class AFLLTOPass : public ModulePass { uint32_t afl_global_id = 1, autodictionary = 1; uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; - uint64_t map_addr = 0x10000; + unsigned long long int map_addr = 0x10000; char * skip_nozero = NULL; }; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index e5f51a6c..811e805c 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -478,7 +478,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { u8 *fname_orig = NULL; /* At the initialization stage, queue_cur is NULL */ - if (afl->queue_cur) fname_orig = afl->queue_cur->fname; + if (afl->queue_cur && !afl->syncing_party) { + + fname_orig = afl->queue_cur->fname; + + } el->afl_custom_queue_new_entry(el->data, fname, fname_orig); -- cgit 1.4.1 From c19d1f0c7519fe7d1234e695c497a78f24aaf8b7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 Apr 2021 12:22:16 +0200 Subject: update grammar-mutator, show better fuzzing strategy yields --- TODO.md | 1 + custom_mutators/grammar_mutator/GRAMMAR_VERSION | 2 +- custom_mutators/grammar_mutator/grammar_mutator | 2 +- docs/Changelog.md | 1 + src/afl-fuzz-stats.c | 72 +++++++++++++++---------- 5 files changed, 49 insertions(+), 29 deletions(-) (limited to 'docs') diff --git a/TODO.md b/TODO.md index dc765ec4..96b24521 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,7 @@ ## Roadmap 3.00+ + - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - CPU affinity for many cores? There seems to be an issue > 96 cores - afl-plot to support multiple plot_data diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION index a3fe6bb1..c7c1948d 100644 --- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION +++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION @@ -1 +1 @@ -b3c4fcf +a2d4e4a diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator index b3c4fcfa..a2d4e4ab 160000 --- a/custom_mutators/grammar_mutator/grammar_mutator +++ b/custom_mutators/grammar_mutator/grammar_mutator @@ -1 +1 @@ -Subproject commit b3c4fcfa6ae28918bc410f7747135eafd4fb7263 +Subproject commit a2d4e4ab966f0581219fbb282f5ac8c89e85ead9 diff --git a/docs/Changelog.md b/docs/Changelog.md index 072320dc..4139a9b3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - better fuzzing strategy yields for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 2c814d90..b9a94ac3 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -861,9 +861,9 @@ void show_stats(afl_state_t *afl) { " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); - if (afl->skip_deterministic) { + if (likely(afl->skip_deterministic)) { - strcpy(tmp, "n/a, n/a, n/a"); + strcpy(tmp, "disabled (default, enable with -D)"); } else { @@ -881,7 +881,7 @@ void show_stats(afl_state_t *afl) { " levels : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->max_depth)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]), @@ -897,7 +897,7 @@ void show_stats(afl_state_t *afl) { " pending : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]), @@ -913,7 +913,7 @@ void show_stats(afl_state_t *afl) { " pend fav : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->pending_favored)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]), @@ -929,7 +929,7 @@ void show_stats(afl_state_t *afl) { " own finds : " cRST "%-10s" bSTG bV "\n", tmp, u_stringify_int(IB(0), afl->queued_discovered)); - if (!afl->skip_deterministic) { + if (unlikely(!afl->skip_deterministic)) { sprintf(tmp, "%s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]), @@ -974,35 +974,52 @@ void show_stats(afl_state_t *afl) { : cRST), tmp); - if (afl->shm.cmplog_mode) { + if (unlikely(afl->afl_env.afl_python_module)) { - sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s", + sprintf(tmp, "%s/%s, ", u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), - u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), - u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON])); + + } else { + + strcpy(tmp, "unused, "); + + } + + if (unlikely(afl->afl_env.afl_custom_mutator_library)) { + + sprintf(tmp, "%s%s/%s, ", tmp, + u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); + + } else { + + strcat(tmp, "unused, "); + + } + + if (unlikely(afl->shm.cmplog_mode)) { + + sprintf(tmp, "%s%s/%s, %s/%s", tmp, u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]), u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]), u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]), u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS])); - SAYF(bV bSTOP " custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", - tmp); - } else { - sprintf(tmp, "%s/%s, %s/%s", - u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), - u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), - u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); - - SAYF(bV bSTOP " py/custom : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", - tmp); + strcat(tmp, "unused, unused "); } - if (!afl->bytes_trim_out) { + SAYF(bV bSTOP "py/custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", + tmp); + + if (likely(afl->disable_trim)) { + + sprintf(tmp, "disabled, "); + + } else if (unlikely(!afl->bytes_trim_out)) { sprintf(tmp, "n/a, "); @@ -1015,12 +1032,13 @@ void show_stats(afl_state_t *afl) { } - if (!afl->blocks_eff_total) { + if (likely(afl->skip_deterministic)) { - u8 tmp2[128]; + strcat(tmp, "disabled"); - sprintf(tmp2, "n/a"); - strcat(tmp, tmp2); + } else if (unlikely(!afl->blocks_eff_total)) { + + strcat(tmp, "n/a"); } else { -- cgit 1.4.1 From ef33193d77cf82e892fe0b807f0433839155315c Mon Sep 17 00:00:00 2001 From: Ujjwal Kirti <64329707+ujjwalkirti@users.noreply.github.com> Date: Fri, 9 Apr 2021 17:09:53 +0530 Subject: Update ideas.md Hey, I noticed there was a spelling error in above documentation for GSOC '21. I have corrected it, you can have a look at it if you want. --- docs/ideas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/ideas.md b/docs/ideas.md index 0130cf61..11c78e49 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -16,7 +16,7 @@ This might look like the afl-fuzz UI, but you can improve on it - and should! Schedulers is a mechanism that selects items from the fuzzing corpus based on strategy and randomness. One scheduler might focus on long paths, -another on rarity of edges disocvered, still another on a combination on +another on rarity of edges discovered, still another on a combination on things. Some of the schedulers in afl++ have to be ported, but you are free to come up with your own if you want to - and see how it performs. -- cgit 1.4.1 From be880f2476963b8ebebe9d8cc196e4e74104c7a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 13:01:50 +0200 Subject: add AFL_EXIT_ON_SEED_ISSUES --- docs/Changelog.md | 3 +++ docs/env_variables.md | 3 +++ include/afl-fuzz.h | 3 ++- include/envs.h | 1 + src/afl-fuzz-init.c | 8 +++++++- src/afl-fuzz-state.c | 7 +++++++ 6 files changed, 23 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 4139a9b3..14a0bdaf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -24,6 +24,9 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in + -i dir crashes the target or results in a timeout. By default + afl++ ignores these and uses them for splicing instead. - afl-cc: - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 8d482e20..1f4dfef9 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,9 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour + which does not allow crashes or timeout seeds in the initial -i corpus. + - `AFL_MAP_SIZE` sets the size of the shared map that afl-fuzz, afl-showmap, afl-tmin and afl-analyze create to gather instrumentation data from the target. This must be equal or larger than the size the target was diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 325168f2..f201782a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -384,7 +384,8 @@ typedef struct afl_env_vars { afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, - afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new; + afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, + afl_exit_on_seed_issues; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, diff --git a/include/envs.h b/include/envs.h index 466ab087..ebe98257 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index e505abd4..b6bfbc29 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -881,7 +881,7 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_TMOUT: - if (afl->timeout_given) { + if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) { /* if we have a timeout but a timeout value was given then always skip. The '+' meaning has been changed! */ @@ -1036,6 +1036,12 @@ void perform_dry_run(afl_state_t *afl) { } + if (afl->afl_env.afl_exit_on_seed_issues) { + + FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits."); + + } + /* Remove from fuzzing queue but keep for splicing */ struct queue_entry *p = afl->queue; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f65ff1bb..28d3339a 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -306,6 +306,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->cycle_schedules = afl->afl_env.afl_cycle_schedules = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_SEED_ISSUES", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_seed_issues = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW", afl_environment_variable_len)) { -- cgit 1.4.1 From 1fabfd5a32ce850912ce623eeabd369b59c70494 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Apr 2021 17:59:11 +0200 Subject: afl-whatsup -d --- afl-whatsup | 45 ++++++++++++++++++++++++++++++++++----------- docs/Changelog.md | 1 + 2 files changed, 35 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/afl-whatsup b/afl-whatsup index e92b24bd..ee20fc2d 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -21,29 +21,37 @@ echo "$0 status check tool for afl-fuzz by Michal Zalewski" echo test "$1" = "-h" -o "$1" = "-hh" && { - echo $0 [-s] output_directory + echo "$0 [-s] [-d] output_directory" echo echo Options: echo -s - skip details and output summary results only + echo -d - include dead fuzzer stats echo exit 1 } -if [ "$1" = "-s" ]; then +unset SUMMARY_ONLY +unset PROCESS_DEAD - SUMMARY_ONLY=1 - DIR="$2" +while [ "$1" = "-s" -o "$1" = "-d" ]; do -else + if [ "$1" = "-s" ]; then + SUMMARY_ONLY=1 + fi - unset SUMMARY_ONLY - DIR="$1" + if [ "$1" = "-d" ]; then + PROCESS_DEAD=1 + fi + + shift -fi +done + +DIR="$1" if [ "$DIR" = "" ]; then - echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2 + echo "Usage: $0 [-s] [-d] afl_sync_dir" 1>&2 echo 1>&2 echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2 echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2 @@ -160,7 +168,12 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do fi DEAD_CNT=$((DEAD_CNT + 1)) - continue + + if [ "$PROCESS_DEAD" = "" ]; then + + continue + + fi fi @@ -257,8 +270,18 @@ echo "=============" echo echo " Fuzzers alive : $ALIVE_CNT" +if [ "$PROCESS_DEAD" = "" ]; then + + TXT="excluded from stats" + +else + + TXT="included in stats" + +fi + if [ ! "$DEAD_CNT" = "0" ]; then - echo " Dead or remote : $DEAD_CNT (excluded from stats)" + echo " Dead or remote : $DEAD_CNT ($TXT)" fi echo " Total run time : $FMT_TIME" diff --git a/docs/Changelog.md b/docs/Changelog.md index 14a0bdaf..bd14e293 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,7 @@ sending a mail to . - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - add -d (dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From 5e72568a455bde8ac389b8b234cbdbbb0d33e015 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 17:52:43 +0200 Subject: ui update --- docs/status_screen.md | 11 +++++++++-- src/afl-fuzz-stats.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/status_screen.md b/docs/status_screen.md index 0329d960..e3abcc5f 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -251,8 +251,9 @@ exceed it by a margin sufficient to be classified as hangs. | arithmetics : 53/2.54M, 0/537k, 0/55.2k | | known ints : 8/322k, 12/1.32M, 10/1.70M | | dictionary : 9/52k, 1/53k, 1/24k | - | havoc : 1903/20.0M, 0/0 | - | trim : 20.31%/9201, 17.05% | + |havoc/splice : 1903/20.0M, 0/0 | + |py/custom/rq : unused, 53/2.54M, unused | + | trim/eff : 20.31%/9201, 17.05% | +-----------------------------------------------------+ ``` @@ -268,6 +269,12 @@ goal. Finally, the third number shows the proportion of bytes that, although not possible to remove, were deemed to have no effect and were excluded from some of the more expensive deterministic fuzzing steps. +Note that when deterministic mutation mode is off (which is the default +because it is not very efficient) the first five lines display +"disabled (default, enable with -D)". + +Only what is activated will have counter shown. + ### Path geometry ``` diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index e0e24a18..009cebf6 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1074,7 +1074,7 @@ void show_stats(afl_state_t *afl) { // //} else { - SAYF(bV bSTOP " trim : " cRST "%-36s " bSTG bV RESET_G1, tmp); + SAYF(bV bSTOP " trim/eff : " cRST "%-36s " bSTG bV RESET_G1, tmp); //} -- cgit 1.4.1 From 92a308133797a1926507361e71b84f8b1eacc754 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Apr 2021 18:24:05 +0200 Subject: fix aflpp qemu hook --- docs/Changelog.md | 1 + utils/aflpp_driver/aflpp_qemu_driver_hook.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index bd14e293..155eec66 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,7 @@ sending a mail to . - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - add -d (dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index 823cc42d..dc58d852 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -3,8 +3,8 @@ #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) -#define REGS_RDI 7 -#define REGS_RSI 6 +#define REGS_RDI 4 +#define REGS_RSI 5 void afl_persistent_hook(uint64_t *regs, uint64_t guest_base, uint8_t *input_buf, uint32_t input_len) { -- cgit 1.4.1 From e41d1183cca02fb4d6398df4fc3e028dfd9c5f72 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 00:41:32 +0200 Subject: fix nits --- GNUmakefile | 2 +- docs/env_variables.md | 4 ++-- qemu_mode/build_qemu_support.sh | 2 ++ src/afl-fuzz-stats.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index a87b2f7b..804bfe08 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -550,7 +550,7 @@ all_done: test_build @test -e SanitizerCoverageLTO.so && echo "[+] LLVM LTO mode for 'afl-cc' successfully built!" || echo "[-] LLVM LTO mode for 'afl-cc' failed to build, this would need LLVM 11+, see instrumentation/README.lto.md how to build it" @test -e afl-gcc-pass.so && echo "[+] gcc_plugin for 'afl-cc' successfully built!" || echo "[-] gcc_plugin for 'afl-cc' failed to build, unless you really need it that is fine - or read instrumentation/README.gcc_plugin.md how to build it" @echo "[+] All done! Be sure to review the README.md - it's pretty short and useful." - @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecific for MacOs.\n\n"; fi + @if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD for fuzzing software not\nspecifically for MacOS.\n\n"; fi @! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.md for advice.\033[0m\n" 2>/dev/null .NOTPARALLEL: clean all diff --git a/docs/env_variables.md b/docs/env_variables.md index 1f4dfef9..0100ffac 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -382,8 +382,8 @@ checks or alter some of the more exotic semantics of the tool: may complain of high load prematurely, especially on systems with low core counts. To avoid the alarming red color, you can set `AFL_NO_CPU_RED`. - - In QEMU mode (-Q), Unicorn mode (-U) and Frida mode (-O), `AFL_PATH` will - be searched for afl-qemu-trace. + - In QEMU mode (-Q) and Frida mode (-O), `AFL_PATH` will + be searched for afl-qemu-trace and afl-frida-trace.so. - In QEMU mode (-Q), setting `AFL_QEMU_CUSTOM_BIN` cause afl-fuzz to skip prepending `afl-qemu-trace` to your command line. Use this if you wish to use a diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 38085389..6436d43a 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -360,6 +360,8 @@ if ! command -v "$CROSS" > /dev/null ; then make -C unsigaction && echo "[+] unsigaction ready" echo "[+] Building libqasan ..." make -C libqasan && echo "[+] unsigaction ready" + echo "[+] Building qemu libfuzzer helpers ..." + make -C ../utils/aflpp_driver else echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction" fi diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index a1559eac..52d9de87 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -866,7 +866,7 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->custom_only)) { - strcpy(tmp, "disabled (custom mutator only mode)"); + strcpy(tmp, "disabled (custom-mutator-only mode)"); } else if (likely(afl->skip_deterministic)) { -- cgit 1.4.1 From 89d4565092367753c70849bb85b220db48ed2710 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 16 Apr 2021 11:45:22 +0200 Subject: update docs --- README.md | 10 +++++----- TODO.md | 1 - docs/Changelog.md | 6 ++++-- docs/ideas.md | 43 +++++++------------------------------------ 4 files changed, 16 insertions(+), 44 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index e7582aff..583db85f 100644 --- a/README.md +++ b/README.md @@ -99,15 +99,15 @@ behaviours and defaults: | Ngram prev_loc Coverage | | x(6) | | | | | | Context Coverage | | x(6) | | | | | | Auto Dictionary | | x(7) | | | | | - | Snapshot LKM Support | | x(8) | x(8) | | (x)(5) | | + | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | - 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8 + 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin 3. (currently unassigned) - 4. with pcguard mode and LTO mode for LLVM >= 11 + 4. with pcguard mode and LTO mode for LLVM 11 and newer 5. upcoming, development in the branch - 6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1 - 7. automatic in LTO mode with LLVM >= 11, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x` + 6. not compatible with LTO instrumentation and needs at least LLVM v4.1 + 7. automatic in LTO mode with LLVM 11 and newer, an extra pass for all LLVM version that writes to a file to use with afl-fuzz' `-x` 8. the snapshot LKM is currently unmaintained due to too many kernel changes coming too fast :-( Among others, the following features and patches have been integrated: diff --git a/TODO.md b/TODO.md index 96b24521..c828d214 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,6 @@ - intel-pt tracer - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - - cmplog: too much tainted bytes, directly add to dict and skip? - parallel builds for source-only targets ## Further down the road diff --git a/docs/Changelog.md b/docs/Changelog.md index 155eec66..9c9a3976 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,8 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - default cmplog level (-l) is now 2, better efficiency. + - cmplog level 3 (-l 3) now performs redqueen on everything. + use with care. - better fuzzing strategy yields for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing @@ -28,11 +30,11 @@ sending a mail to . -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - afl-cc: - - Leak Sanitizer support (AFL_USE_LSAN) added by Joshua Rogers, thanks! + - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - - add -d (dead fuzzer stats) to afl-whatsup + - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/ideas.md b/docs/ideas.md index 11c78e49..e25d3ba6 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -3,42 +3,6 @@ In the following, we describe a variety of ideas that could be implemented for future AFL++ versions. -# GSoC 2021 - -All GSoC 2021 projects will be in the Rust development language! - -## UI for libaflrs - -Write a user interface to libaflrs, the upcoming backend of afl++. -This might look like the afl-fuzz UI, but you can improve on it - and should! - -## Schedulers for libaflrs - -Schedulers is a mechanism that selects items from the fuzzing corpus based -on strategy and randomness. One scheduler might focus on long paths, -another on rarity of edges discovered, still another on a combination on -things. Some of the schedulers in afl++ have to be ported, but you are free -to come up with your own if you want to - and see how it performs. - -## Forkserver support for libaflrs - -The current libaflrs implementation fuzzes in-memory, however obviously we -want to support afl instrumented binaries as well. -Hence a forkserver support needs to be implemented - forking off the target -and talking to the target via a socketpair and the communication protocol -within. - -## More Observers for libaflrs - -An observer is measuring functionality that looks at the target being fuzzed -and documents something about it. In traditional fuzzing this is the coverage -in the target, however we want to add various more observers, e.g. stack depth, -heap usage, etc. - this is a topic for an experienced Rust developer. - -# Generic ideas and wishlist - NOT PART OF GSoC 2021 ! - -The below list is not part of GSoC 2021. - ## Analysis software Currently analysis is done by using afl-plot, which is rather outdated. @@ -65,6 +29,13 @@ the current Unicorn instrumentation. Mentor: any +## Support other programming languages + +Other programming languages also use llvm hence they could (easily?) supported +for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ... + +Mentor: vanhauser-thc + ## Machine Learning Something with machine learning, better than [NEUZZ](https://github.com/dongdongshe/neuzz) :-) -- cgit 1.4.1 From 3b5fa3632b0e482b2915709d7fbec827e1d997b9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 19 Apr 2021 11:05:42 +0200 Subject: drop support for llvm < 6.0 --- GNUmakefile.llvm | 8 ++++---- README.md | 4 ++-- docs/Changelog.md | 1 + instrumentation/README.llvm.md | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 61c17e92..2d50badc 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -36,7 +36,7 @@ ifeq "$(SYS)" "OpenBSD" LLVM_CONFIG ?= $(BIN_PATH)/llvm-config HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1) ifeq "$(HAS_OPT)" "1" - $(warning llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") + $(warning llvm_mode needs a complete llvm installation (versions 6.0 up to 12) -> e.g. "pkg_add llvm-7.0.1p9") endif else LLVM_CONFIG ?= llvm-config @@ -45,7 +45,7 @@ endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^[0-2]\.' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 ) LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 ) @@ -61,7 +61,7 @@ ifeq "$(LLVMVER)" "" endif ifeq "$(LLVM_UNSUPPORTED)" "1" - $(error llvm_mode only supports llvm from version 3.4 onwards) + $(error llvm_mode only supports llvm from version 6.0 onwards) endif ifeq "$(LLVM_TOO_NEW)" "1" @@ -346,7 +346,7 @@ no_build: test_deps: @echo "[*] Checking for working 'llvm-config'..." ifneq "$(LLVM_APPLE_XCODE)" "1" - @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-3.5 or something like that.)"; exit 1 ) + @type $(LLVM_CONFIG) >/dev/null 2>&1 || ( echo "[-] Oops, can't find 'llvm-config'. Install clang or set \$$LLVM_CONFIG or \$$PATH beforehand."; echo " (Sometimes, the binary will be named llvm-config-11 or something like that.)"; exit 1 ) endif @echo "[*] Checking for working '$(CC)'..." @type $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 ) diff --git a/README.md b/README.md index 583db85f..4a0f3574 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. @@ -293,7 +293,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 3.3+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ diff --git a/docs/Changelog.md b/docs/Changelog.md index 9c9a3976..520b13b1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -30,6 +30,7 @@ sending a mail to . -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - afl-cc: + - We do not support llvm versions prior 6.0 anymore - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index adce6c1d..0937a328 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -6,7 +6,7 @@ ## 1) Introduction -! llvm_mode works with llvm versions 3.4 up to 12 ! +! llvm_mode works with llvm versions 6.0 up to 12 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude -- cgit 1.4.1 From a3f8fc5d1ccabc455e28157ee86211f0c11c81a3 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 26 Apr 2021 16:03:08 +0200 Subject: moved custom_mutator examples --- custom_mutators/README.md | 8 + custom_mutators/examples/Makefile | 7 + custom_mutators/examples/README.md | 35 ++ custom_mutators/examples/XmlMutatorMin.py | 348 ++++++++++++++++++++ custom_mutators/examples/common.py | 40 +++ custom_mutators/examples/custom_mutator_helpers.h | 342 ++++++++++++++++++++ custom_mutators/examples/example.c | 376 ++++++++++++++++++++++ custom_mutators/examples/example.py | 187 +++++++++++ custom_mutators/examples/post_library_gif.so.c | 165 ++++++++++ custom_mutators/examples/post_library_png.so.c | 163 ++++++++++ custom_mutators/examples/simple-chunk-replace.py | 66 ++++ custom_mutators/examples/simple_example.c | 74 +++++ custom_mutators/examples/wrapper_afl_min.py | 123 +++++++ docs/custom_mutators.md | 4 +- docs/life_pro_tips.md | 2 +- qemu_mode/README.md | 4 +- test/test-custom-mutators.sh | 4 +- utils/custom_mutators/Makefile | 7 - utils/custom_mutators/README.md | 35 -- utils/custom_mutators/XmlMutatorMin.py | 348 -------------------- utils/custom_mutators/common.py | 40 --- utils/custom_mutators/custom_mutator_helpers.h | 342 -------------------- utils/custom_mutators/example.c | 376 ---------------------- utils/custom_mutators/example.py | 187 ----------- utils/custom_mutators/post_library_gif.so.c | 165 ---------- utils/custom_mutators/post_library_png.so.c | 163 ---------- utils/custom_mutators/simple-chunk-replace.py | 66 ---- utils/custom_mutators/simple_example.c | 74 ----- utils/custom_mutators/wrapper_afl_min.py | 123 ------- 29 files changed, 1941 insertions(+), 1933 deletions(-) create mode 100644 custom_mutators/examples/Makefile create mode 100644 custom_mutators/examples/README.md create mode 100644 custom_mutators/examples/XmlMutatorMin.py create mode 100644 custom_mutators/examples/common.py create mode 100644 custom_mutators/examples/custom_mutator_helpers.h create mode 100644 custom_mutators/examples/example.c create mode 100644 custom_mutators/examples/example.py create mode 100644 custom_mutators/examples/post_library_gif.so.c create mode 100644 custom_mutators/examples/post_library_png.so.c create mode 100644 custom_mutators/examples/simple-chunk-replace.py create mode 100644 custom_mutators/examples/simple_example.c create mode 100644 custom_mutators/examples/wrapper_afl_min.py delete mode 100644 utils/custom_mutators/Makefile delete mode 100644 utils/custom_mutators/README.md delete mode 100644 utils/custom_mutators/XmlMutatorMin.py delete mode 100644 utils/custom_mutators/common.py delete mode 100644 utils/custom_mutators/custom_mutator_helpers.h delete mode 100644 utils/custom_mutators/example.c delete mode 100644 utils/custom_mutators/example.py delete mode 100644 utils/custom_mutators/post_library_gif.so.c delete mode 100644 utils/custom_mutators/post_library_png.so.c delete mode 100644 utils/custom_mutators/simple-chunk-replace.py delete mode 100644 utils/custom_mutators/simple_example.c delete mode 100644 utils/custom_mutators/wrapper_afl_min.py (limited to 'docs') diff --git a/custom_mutators/README.md b/custom_mutators/README.md index b0444c85..5e1d0fe6 100644 --- a/custom_mutators/README.md +++ b/custom_mutators/README.md @@ -3,6 +3,14 @@ Custom mutators enhance and alter the mutation strategies of afl++. For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md). +## Examples + +The `./examples` folder contains examples for custom mutators in python and C. + +## Rust + +In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`. + ## The afl++ Grammar Mutator If you use git to clone afl++, then the following will incorporate our diff --git a/custom_mutators/examples/Makefile b/custom_mutators/examples/Makefile new file mode 100644 index 00000000..9849f3f4 --- /dev/null +++ b/custom_mutators/examples/Makefile @@ -0,0 +1,7 @@ +all: libexamplemutator.so + +libexamplemutator.so: + $(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so + +clean: + rm -rf libexamplemutator.so diff --git a/custom_mutators/examples/README.md b/custom_mutators/examples/README.md new file mode 100644 index 00000000..655f7a5e --- /dev/null +++ b/custom_mutators/examples/README.md @@ -0,0 +1,35 @@ +# Examples for the custom mutator + +These are example and helper files for the custom mutator feature. +See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information + +Note that if you compile with python3.7 you must use python3 scripts, and if +you use python2.7 to compile python2 scripts! + +simple_example.c - most simplest example. generates a random sized buffer + filled with 'A' + +example.c - this is a simple example written in C and should be compiled to a + shared library. Use make to compile it and produce libexamplemutator.so + +example.py - this is the template you can use, the functions are there but they + are empty + +post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF + +post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG + +simple-chunk-replace.py - this is a simple example where chunks are replaced + +common.py - this can be used for common functions and helpers. + the examples do not use this though. But you can :) + +wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py + +XmlMutatorMin.py - module for XML mutation + +custom_mutator_helpers.h is an header that defines some helper routines +like surgical_havoc_mutate() that allow to perform a randomly chosen +mutation from a subset of the havoc mutations. +If you do so, you have to specify -I /path/to/AFLplusplus/include when +compiling. diff --git a/custom_mutators/examples/XmlMutatorMin.py b/custom_mutators/examples/XmlMutatorMin.py new file mode 100644 index 00000000..3e6cd0ff --- /dev/null +++ b/custom_mutators/examples/XmlMutatorMin.py @@ -0,0 +1,348 @@ +#!/usr/bin/python + +""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """ + +from __future__ import print_function +from copy import deepcopy +from lxml import etree as ET +import random, re, io + + +########################### +# The XmlMutatorMin class # +########################### + + +class XmlMutatorMin: + + """ + Optionals parameters: + seed Seed used by the PRNG (default: "RANDOM") + verbose Verbosity (default: False) + """ + + def __init__(self, seed="RANDOM", verbose=False): + + """ Initialize seed, database and mutators """ + + # Verbosity + self.verbose = verbose + + # Initialize PRNG + self.seed = str(seed) + if self.seed == "RANDOM": + random.seed() + else: + if self.verbose: + print("Static seed '%s'" % self.seed) + random.seed(self.seed) + + # Initialize input and output documents + self.input_tree = None + self.tree = None + + # High-level mutators (no database needed) + hl_mutators_delete = [ + "del_node_and_children", + "del_node_but_children", + "del_attribute", + "del_content", + ] # Delete items + hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values + + # Exposed mutators + self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete + + def __parse_xml(self, xml): + + """ Parse an XML string. Basic wrapper around lxml.parse() """ + + try: + # Function parse() takes care of comments / DTD / processing instructions / ... + tree = ET.parse(io.BytesIO(xml)) + except ET.ParseError: + raise RuntimeError("XML isn't well-formed!") + except LookupError as e: + raise RuntimeError(e) + + # Return a document wrapper + return tree + + def __exec_among(self, module, functions, min_times, max_times): + + """ Randomly execute $functions between $min and $max times """ + + for i in xrange(random.randint(min_times, max_times)): + # Function names are mangled because they are "private" + getattr(module, "_XmlMutatorMin__" + random.choice(functions))() + + def __serialize_xml(self, tree): + + """ Serialize a XML document. Basic wrapper around lxml.tostring() """ + + return ET.tostring( + tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding + ) + + def __ver(self, version): + + """ Helper for displaying lxml version numbers """ + + return ".".join(map(str, version)) + + def reset(self): + + """ Reset the mutator """ + + self.tree = deepcopy(self.input_tree) + + def init_from_string(self, input_string): + + """ Initialize the mutator from a XML string """ + + # Get a pointer to the top-element + self.input_tree = self.__parse_xml(input_string) + + # Get a working copy + self.tree = deepcopy(self.input_tree) + + def save_to_string(self): + + """ Return the current XML document as UTF-8 string """ + + # Return a text version of the tree + return self.__serialize_xml(self.tree) + + def __pick_element(self, exclude_root_node=False): + + """ Pick a random element from the current document """ + + # Get a list of all elements, but nodes like PI and comments + elems = list(self.tree.getroot().iter(tag=ET.Element)) + + # Is the root node excluded? + if exclude_root_node: + start = 1 + else: + start = 0 + + # Pick a random element + try: + elem_id = random.randint(start, len(elems) - 1) + elem = elems[elem_id] + except ValueError: + # Should only occurs if "exclude_root_node = True" + return (None, None) + + return (elem_id, elem) + + def __fuzz_attribute(self): + + """ Fuzz (part of) an attribute value """ + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Get all the attributes + attribs = rand_elem.keys() + + # Is there attributes? + if len(attribs) < 1: + if self.verbose: + print("No attribute: can't replace!") + return + + # Pick a random attribute + rand_attrib_id = random.randint(0, len(attribs) - 1) + rand_attrib = attribs[rand_attrib_id] + + # We have the attribute to modify + # Get its value + attrib_value = rand_elem.get(rand_attrib) + # print("- Value: " + attrib_value) + + # Should we work on the whole value? + func_call = "(?P[a-zA-Z:\-]+)\((?P.*?)\)" + p = re.compile(func_call) + l = p.findall(attrib_value) + if random.choice((True, False)) and l: + # Randomly pick one the function calls + (func, args) = random.choice(l) + # Split by "," and randomly pick one of the arguments + value = random.choice(args.split(",")) + # Remove superfluous characters + unclean_value = value + value = value.strip(" ").strip("'") + # print("Selected argument: [%s]" % value) + else: + value = attrib_value + + # For each type, define some possible replacement values + choices_number = ( + "0", + "11111", + "-128", + "2", + "-1", + "1/3", + "42/0", + "1094861636 idiv 1.0", + "-1123329771506872 idiv 3.8", + "17=$numericRTF", + str(3 + random.randrange(0, 100)), + ) + + choices_letter = ( + "P" * (25 * random.randrange(1, 100)), + "%s%s%s%s%s%s", + "foobar", + ) + + choices_alnum = ( + "Abc123", + "020F0302020204030204", + "020F0302020204030204" * (random.randrange(5, 20)), + ) + + # Fuzz the value + if random.choice((True, False)) and value == "": + + # Empty + new_value = value + + elif random.choice((True, False)) and value.isdigit(): + + # Numbers + new_value = random.choice(choices_number) + + elif random.choice((True, False)) and value.isalpha(): + + # Letters + new_value = random.choice(choices_letter) + + elif random.choice((True, False)) and value.isalnum(): + + # Alphanumeric + new_value = random.choice(choices_alnum) + + else: + + # Default type + new_value = random.choice(choices_alnum + choices_letter + choices_number) + + # If we worked on a substring, apply changes to the whole string + if value != attrib_value: + # No ' around empty values + if new_value != "" and value != "": + new_value = "'" + new_value + "'" + # Apply changes + new_value = attrib_value.replace(unclean_value, new_value) + + # Log something + if self.verbose: + print( + "Fuzzing attribute #%i '%s' of tag #%i '%s'" + % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) + ) + + # Modify the attribute + rand_elem.set(rand_attrib, new_value.decode("utf-8")) + + def __del_node_and_children(self): + + """High-level minimizing mutator + Delete a random node and its children (i.e. delete a random tree)""" + + self.__del_node(True) + + def __del_node_but_children(self): + + """High-level minimizing mutator + Delete a random node but its children (i.e. link them to the parent of the deleted node)""" + + self.__del_node(False) + + def __del_node(self, delete_children): + + """ Called by the __del_node_* mutators """ + + # Select a node to modify (but the root one) + (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True) + + # If the document includes only a top-level element + # Then we can't pick a element (given that "exclude_root_node = True") + + # Is the document deep enough? + if rand_elem is None: + if self.verbose: + print("Can't delete a node: document not deep enough!") + return + + # Log something + if self.verbose: + but_or_and = "and" if delete_children else "but" + print( + "Deleting tag #%i '%s' %s its children" + % (rand_elem_id, rand_elem.tag, but_or_and) + ) + + if delete_children is False: + # Link children of the random (soon to be deleted) node to its parent + for child in rand_elem: + rand_elem.getparent().append(child) + + # Remove the node + rand_elem.getparent().remove(rand_elem) + + def __del_content(self): + + """High-level minimizing mutator + Delete the attributes and children of a random node""" + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Log something + if self.verbose: + print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) + + # Reset the node + rand_elem.clear() + + def __del_attribute(self): + + """High-level minimizing mutator + Delete a random attribute from a random node""" + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Get all the attributes + attribs = rand_elem.keys() + + # Is there attributes? + if len(attribs) < 1: + if self.verbose: + print("No attribute: can't delete!") + return + + # Pick a random attribute + rand_attrib_id = random.randint(0, len(attribs) - 1) + rand_attrib = attribs[rand_attrib_id] + + # Log something + if self.verbose: + print( + "Deleting attribute #%i '%s' of tag #%i '%s'" + % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) + ) + + # Delete the attribute + rand_elem.attrib.pop(rand_attrib) + + def mutate(self, min=1, max=5): + + """ Execute some high-level mutators between $min and $max times, then some medium-level ones """ + + # High-level mutation + self.__exec_among(self, self.hl_mutators_all, min, max) diff --git a/custom_mutators/examples/common.py b/custom_mutators/examples/common.py new file mode 100644 index 00000000..44a5056a --- /dev/null +++ b/custom_mutators/examples/common.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Module containing functions shared between multiple AFL modules + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +from __future__ import print_function +import random +import os +import re + + +def randel(l): + if not l: + return None + return l[random.randint(0, len(l) - 1)] + + +def randel_pop(l): + if not l: + return None + return l.pop(random.randint(0, len(l) - 1)) + + +def write_exc_example(data, exc): + exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc)) + + if not os.path.exists(exc_name): + with open(exc_name, "w") as f: + f.write(data) diff --git a/custom_mutators/examples/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h new file mode 100644 index 00000000..62e6efba --- /dev/null +++ b/custom_mutators/examples/custom_mutator_helpers.h @@ -0,0 +1,342 @@ +#ifndef CUSTOM_MUTATOR_HELPERS +#define CUSTOM_MUTATOR_HELPERS + +#include "config.h" +#include "types.h" +#include + +#define INITIAL_GROWTH_SIZE (64) + +#define RAND_BELOW(limit) (rand() % (limit)) + +/* Use in a struct: creates a name_buf and a name_size variable. */ +#define BUF_VAR(type, name) \ + type * name##_buf; \ + size_t name##_size; +/* this fills in `&structptr->something_buf, &structptr->something_size`. */ +#define BUF_PARAMS(struct, name) \ + (void **)&struct->name##_buf, &struct->name##_size + +typedef struct { + +} afl_t; + +static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { + + static s8 interesting_8[] = {INTERESTING_8}; + static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; + static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; + + switch (RAND_BELOW(12)) { + + case 0: { + + /* Flip a single bit somewhere. Spooky! */ + + s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); + + out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); + + break; + + } + + case 1: { + + /* Set byte to interesting value. */ + + u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; + out_buf[(RAND_BELOW(end - begin) + begin)] = val; + + break; + + } + + case 2: { + + /* Set word to interesting value, randomly choosing endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u16 *)(out_buf + byte_idx) = + interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; + break; + case 1: + *(u16 *)(out_buf + byte_idx) = + SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); + break; + + } + + break; + + } + + case 3: { + + /* Set dword to interesting value, randomly choosing endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u32 *)(out_buf + byte_idx) = + interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u32 *)(out_buf + byte_idx) = + SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 4: { + + /* Set qword to interesting value, randomly choosing endian. */ + + if (end - begin < 8) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 7) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u64 *)(out_buf + byte_idx) = + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u64 *)(out_buf + byte_idx) = SWAP64( + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 5: { + + /* Randomly subtract from byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 6: { + + /* Randomly add to byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 7: { + + /* Randomly subtract from word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 8: { + + /* Randomly add to word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 9: { + + /* Randomly subtract from dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 10: { + + /* Randomly add to dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 11: { + + /* Just set a random byte to a random value. Because, + why not. We use XOR with 1-255 to eliminate the + possibility of a no-op. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); + + break; + + } + + } + +} + +/* This function calculates the next power of 2 greater or equal its argument. + @return The rounded up power of 2 (if no overflow) or 0 on overflow. +*/ +static inline size_t next_pow2(size_t in) { + + if (in == 0 || in > (size_t)-1) + return 0; /* avoid undefined behaviour under-/overflow */ + size_t out = in - 1; + out |= out >> 1; + out |= out >> 2; + out |= out >> 4; + out |= out >> 8; + out |= out >> 16; + return out + 1; + +} + +/* This function makes sure *size is > size_needed after call. + It will realloc *buf otherwise. + *size will grow exponentially as per: + https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ + Will return NULL and free *buf if size_needed is <1 or realloc failed. + @return For convenience, this function returns *buf. + */ +static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { + + /* No need to realloc */ + if (likely(size_needed && *size >= size_needed)) return *buf; + + /* No initial size was set */ + if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; + + /* grow exponentially */ + size_t next_size = next_pow2(size_needed); + + /* handle overflow */ + if (!next_size) { next_size = size_needed; } + + /* alloc */ + *buf = realloc(*buf, next_size); + *size = *buf ? next_size : 0; + + return *buf; + +} + +/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ +static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, + size_t *size2) { + + void * scratch_buf = *buf1; + size_t scratch_size = *size1; + *buf1 = *buf2; + *size1 = *size2; + *buf2 = scratch_buf; + *size2 = scratch_size; + +} + +#undef INITIAL_GROWTH_SIZE + +#endif + diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c new file mode 100644 index 00000000..23add128 --- /dev/null +++ b/custom_mutators/examples/example.c @@ -0,0 +1,376 @@ +/* + New Custom Mutator for AFL++ + Written by Khaled Yakdan + Andrea Fioraldi + Shengtuo Hu + Dominik Maier +*/ + +// You need to use -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#define DATA_SIZE (100) + +static const char *commands[] = { + + "GET", + "PUT", + "DEL", + +}; + +typedef struct my_mutator { + + afl_t *afl; + + // any additional data here! + size_t trim_size_current; + int trimmming_steps; + int cur_step; + + // Reused buffers: + BUF_VAR(u8, fuzz); + BUF_VAR(u8, data); + BUF_VAR(u8, havoc); + BUF_VAR(u8, trim); + BUF_VAR(u8, post_process); + +} my_mutator_t; + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); // needed also by surgical_havoc_mutate() + + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +/** + * Perform custom mutations on a given input + * + * (Optional for now. Required in the future) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + // Make sure that the packet size does not exceed the maximum size expected by + // the fuzzer + size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; + + // maybe_grow is optimized to be quick for reused buffers. + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + // Randomly select a command string to add as a header to the packet + memcpy(mutated_out, commands[rand() % 3], 3); + + // Mutate the payload of the packet + int i; + for (i = 0; i < 8; ++i) { + + // Randomly perform one of the (no len modification) havoc mutations + surgical_havoc_mutate(mutated_out, 3, mutated_size); + + } + + *out_buf = mutated_out; + return mutated_size; + +} + +/** + * A post-processing function to use right before AFL writes the test case to + * disk in order to execute the target. + * + * (Optional) If this functionality is not needed, simply don't define this + * function. + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Buffer containing the test case to be executed + * @param[in] buf_size Size of the test case + * @param[out] out_buf Pointer to the buffer containing the test case after + * processing. External library should allocate memory for out_buf. + * The buf pointer may be reused (up to the given buf_size); + * @return Size of the output buffer after processing or the needed amount. + * A return of 0 indicates an error. + */ +size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, + size_t buf_size, uint8_t **out_buf) { + + uint8_t *post_process_buf = + maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); + if (!post_process_buf) { + + perror("custom mutator realloc failed."); + *out_buf = NULL; + return 0; + + } + + memcpy(post_process_buf + 5, buf, buf_size); + post_process_buf[0] = 'A'; + post_process_buf[1] = 'F'; + post_process_buf[2] = 'L'; + post_process_buf[3] = '+'; + post_process_buf[4] = '+'; + + *out_buf = post_process_buf; + + return buf_size + 5; + +} + +/** + * This method is called at the start of each trimming operation and receives + * the initial buffer. It should return the amount of iteration steps possible + * on this input (e.g. if your input has n elements and you want to remove + * them one by one, return n, if you do a binary search, return log(n), + * and so on...). + * + * If your trimming algorithm doesn't allow you to determine the amount of + * (remaining) steps easily (esp. while running), then you can alternatively + * return 1 here and always return 0 in post_trim until you are finished and + * no steps remain. In that case, returning 1 in post_trim will end the + * trimming routine. The whole current index/max iterations stuff is only used + * to show progress. + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param buf Buffer containing the test case + * @param buf_size Size of the test case + * @return The amount of possible iteration steps to trim the input. + * negative on error. + */ +int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, + size_t buf_size) { + + // We simply trim once + data->trimmming_steps = 1; + + data->cur_step = 0; + + if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { + + perror("init_trim grow"); + return -1; + + } + + memcpy(data->trim_buf, buf, buf_size); + + data->trim_size_current = buf_size; + + return data->trimmming_steps; + +} + +/** + * This method is called for each trimming operation. It doesn't have any + * arguments because we already have the initial buffer from init_trim and we + * can memorize the current state in *data. This can also save + * reparsing steps for each iteration. It should return the trimmed input + * buffer, where the returned data must not exceed the initial input data in + * length. Returning anything that is larger than the original data (passed + * to init_trim) will result in a fatal abort of AFLFuzz. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[out] out_buf Pointer to the buffer containing the trimmed test case. + * External library should allocate memory for out_buf. + * AFL++ will not release the memory after saving the test case. + * Keep a ref in *data. + * *out_buf = NULL is treated as error. + * @return Pointer to the size of the trimmed test case + */ +size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { + + *out_buf = data->trim_buf; + + // Remove the last byte of the trimming input + return data->trim_size_current - 1; + +} + +/** + * This method is called after each trim operation to inform you if your + * trimming step was successful or not (in terms of coverage). If you receive + * a failure here, you should reset your input to the last known good state. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param success Indicates if the last trim operation was successful. + * @return The next trim iteration index (from 0 to the maximum amount of + * steps returned in init_trim). negative ret on failure. + */ +int32_t afl_custom_post_trim(my_mutator_t *data, int success) { + + if (success) { + + ++data->cur_step; + return data->cur_step; + + } + + return data->trimmming_steps; + +} + +/** + * Perform a single custom mutation on a given input. + * This mutation is stacked with the other muatations in havoc. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to the input data to be mutated and the mutated + * output + * @param[in] buf_size Size of input data + * @param[out] out_buf The output buffer. buf can be reused, if the content + * fits. *out_buf = NULL is treated as error. + * @param[in] max_size Maximum size of the mutated output. The mutation must + * not produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { + + if (buf_size == 0) { + + *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); + if (!*out_buf) { + + perror("custom havoc: maybe_grow"); + return 0; + + } + + **out_buf = rand() % 256; + buf_size = 1; + + } else { + + // We reuse buf here. It's legal and faster. + *out_buf = buf; + + } + + size_t victim = rand() % buf_size; + (*out_buf)[victim] += rand() % 10; + + return buf_size; + +} + +/** + * Return the probability (in percentage) that afl_custom_havoc_mutation + * is called in havoc. By default it is 6 %. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @return The probability (0-100). + */ +uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { + + return 5; // 5 % + +} + +/** + * Determine whether the fuzzer should fuzz the queue entry or not. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param filename File name of the test case in the queue entry + * @return Return True(1) if the fuzzer will fuzz the queue entry, and + * False(0) otherwise. + */ +uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { + + return 1; + +} + +/** + * Allow for additional analysis (e.g. calling a different tool that does a + * different kind of coverage and saves this for the custom mutator). + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param filename_new_queue File name of the new queue entry + * @param filename_orig_queue File name of the original queue entry + */ +void afl_custom_queue_new_entry(my_mutator_t * data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { + + /* Additional analysis on the original or new test case */ + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->post_process_buf); + free(data->havoc_buf); + free(data->data_buf); + free(data->fuzz_buf); + free(data->trim_buf); + free(data); + +} + diff --git a/custom_mutators/examples/example.py b/custom_mutators/examples/example.py new file mode 100644 index 00000000..3a6d22e4 --- /dev/null +++ b/custom_mutators/examples/example.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Example Python Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +import random + + +COMMANDS = [ + b"GET", + b"PUT", + b"DEL", + b"AAAAAAAAAAAAAAAAA", +] + + +def init(seed): + """ + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + """ + random.seed(seed) + + +def deinit(): + pass + + +def fuzz(buf, add_buf, max_size): + """ + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + """ + ret = bytearray(100) + + ret[:3] = random.choice(COMMANDS) + + return ret + + +# Uncomment and implement the following methods if you want to use a custom +# trimming algorithm. See also the documentation for a better API description. + +# def init_trim(buf): +# ''' +# Called per trimming iteration. +# +# @type buf: bytearray +# @param buf: The buffer that should be trimmed. +# +# @rtype: int +# @return: The maximum number of trimming steps. +# ''' +# global ... +# +# # Initialize global variables +# +# # Figure out how many trimming steps are possible. +# # If this is not possible for your trimming, you can +# # return 1 instead and always return 0 in post_trim +# # until you are done (then you return 1). +# +# return steps +# +# def trim(): +# ''' +# Called per trimming iteration. +# +# @rtype: bytearray +# @return: A new bytearray containing the trimmed data. +# ''' +# global ... +# +# # Implement the actual trimming here +# +# return bytearray(...) +# +# def post_trim(success): +# ''' +# Called after each trimming operation. +# +# @type success: bool +# @param success: Indicates if the last trim operation was successful. +# +# @rtype: int +# @return: The next trim index (0 to max number of steps) where max +# number of steps indicates the trimming is done. +# ''' +# global ... +# +# if not success: +# # Restore last known successful input, determine next index +# else: +# # Just determine the next index, based on what was successfully +# # removed in the last step +# +# return next_index +# +# def post_process(buf): +# ''' +# Called just before the execution to write the test case in the format +# expected by the target +# +# @type buf: bytearray +# @param buf: The buffer containing the test case to be executed +# +# @rtype: bytearray +# @return: The buffer containing the test case after +# ''' +# return buf +# +# def havoc_mutation(buf, max_size): +# ''' +# Perform a single custom mutation on a given input. +# +# @type buf: bytearray +# @param buf: The buffer that should be mutated. +# +# @type max_size: int +# @param max_size: Maximum size of the mutated output. The mutation must not +# produce data larger than max_size. +# +# @rtype: bytearray +# @return: A new bytearray containing the mutated data +# ''' +# return mutated_buf +# +# def havoc_mutation_probability(): +# ''' +# Called for each `havoc_mutation`. Return the probability (in percentage) +# that `havoc_mutation` is called in havoc. Be default it is 6%. +# +# @rtype: int +# @return: The probability (0-100) +# ''' +# return prob +# +# def queue_get(filename): +# ''' +# Called at the beginning of each fuzz iteration to determine whether the +# test case should be fuzzed +# +# @type filename: str +# @param filename: File name of the test case in the current queue entry +# +# @rtype: bool +# @return: Return True if the custom mutator decides to fuzz the test case, +# and False otherwise +# ''' +# return True +# +# def queue_new_entry(filename_new_queue, filename_orig_queue): +# ''' +# Called after adding a new test case to the queue +# +# @type filename_new_queue: str +# @param filename_new_queue: File name of the new queue entry +# +# @type filename_orig_queue: str +# @param filename_orig_queue: File name of the original queue entry +# ''' +# pass diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c new file mode 100644 index 00000000..ac10f409 --- /dev/null +++ b/custom_mutators/examples/post_library_gif.so.c @@ -0,0 +1,165 @@ +/* + american fuzzy lop++ - postprocessor library example + -------------------------------------------------- + + Originally written by Michal Zalewski + Edited by Dominik Maier, 2020 + + Copyright 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Postprocessor libraries can be passed to afl-fuzz to perform final cleanup + of any mutated test cases - for example, to fix up checksums in PNG files. + + Please heed the following warnings: + + 1) In almost all cases, it is more productive to comment out checksum logic + in the targeted binary (as shown in ../libpng_no_checksum/). One possible + exception is the process of fuzzing binary-only software in QEMU mode. + + 2) The use of postprocessors for anything other than checksums is + questionable and may cause more harm than good. AFL is normally pretty good + about dealing with length fields, magic values, etc. + + 3) Postprocessors that do anything non-trivial must be extremely robust to + gracefully handle malformed data and other error conditions - otherwise, + they will crash and take afl-fuzz down with them. Be wary of reading past + *len and of integer overflows when calculating file offsets. + + In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, + honestly know what you're doing =) + + With that out of the way: the postprocessor library is passed to afl-fuzz + via AFL_POST_LIBRARY. The library must be compiled with: + + gcc -shared -Wall -O3 post_library.so.c -o post_library.so + + AFL will call the afl_custom_post_process() function for every mutated output + buffer. From there, you have three choices: + + 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` + and return the original `len`. + + 2) If you want to skip this test case altogether and have AFL generate a + new one, return 0 or set `*out_buf = NULL`. + Use this sparingly - it's faster than running the target program + with patently useless inputs, but still wastes CPU time. + + 3) If you want to modify the test case, allocate an appropriately-sized + buffer, move the data into that buffer, make the necessary changes, and + then return the new pointer as out_buf. Return an appropriate len + afterwards. + + Note that the buffer will *not* be freed for you. To avoid memory leaks, + you need to free it or reuse it on subsequent calls (as shown below). + + *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** + + Aight. The example below shows a simple postprocessor that tries to make + sure that all input files start with "GIF89a". + + PS. If you don't like C, you can try out the unix-based wrapper from + Ben Nagy instead: https://github.com/bnagy/aflfix + + */ + +#include +#include +#include + +/* Header that must be present at the beginning of every test case: */ + +#define HEADER "GIF89a" + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +/* The actual postprocessor routine called by afl-fuzz: */ + +size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, + unsigned int len, unsigned char **out_buf) { + + /* Skip execution altogether for buffers shorter than 6 bytes (just to + show how it's done). We can trust len to be sane. */ + + if (len < strlen(HEADER)) return 0; + + /* Do nothing for buffers that already start with the expected header. */ + + if (!memcmp(in_buf, HEADER, strlen(HEADER))) { + + *out_buf = in_buf; + return len; + + } + + /* Allocate memory for new buffer, reusing previous allocation if + possible. */ + + *out_buf = realloc(data->buf, len); + + /* If we're out of memory, the most graceful thing to do is to return the + original buffer and give up on modifying it. Let AFL handle OOM on its + own later on. */ + + if (!*out_buf) { + + *out_buf = in_buf; + return len; + + } + + /* Copy the original data to the new location. */ + + memcpy(*out_buf, in_buf, len); + + /* Insert the new header. */ + + memcpy(*out_buf, HEADER, strlen(HEADER)); + + /* Return the new len. It hasn't changed, so it's just len. */ + + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c new file mode 100644 index 00000000..941f7e55 --- /dev/null +++ b/custom_mutators/examples/post_library_png.so.c @@ -0,0 +1,163 @@ +/* + american fuzzy lop++ - postprocessor for PNG + ------------------------------------------ + + Originally written by Michal Zalewski + + Copyright 2015 Google Inc. All rights reserved. + Adapted to the new API, 2020 by Dominik Maier + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + See post_library.so.c for a general discussion of how to implement + postprocessors. This specific postprocessor attempts to fix up PNG + checksums, providing a slightly more complicated example than found + in post_library.so.c. + + Compile with: + + gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz + + */ + +#include +#include +#include +#include +#include + +#include + +/* A macro to round an integer up to 4 kB. */ + +#define UP4K(_i) ((((_i) >> 12) + 1) << 12) + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, + unsigned int len, + const unsigned char **out_buf) { + + unsigned char *new_buf = (unsigned char *)in_buf; + unsigned int pos = 8; + + /* Don't do anything if there's not enough room for the PNG header + (8 bytes). */ + + if (len < 8) { + + *out_buf = in_buf; + return len; + + } + + /* Minimum size of a zero-length PNG chunk is 12 bytes; if we + don't have that, we can bail out. */ + + while (pos + 12 <= len) { + + unsigned int chunk_len, real_cksum, file_cksum; + + /* Chunk length is the first big-endian dword in the chunk. */ + + chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); + + /* Bail out if chunk size is too big or goes past EOF. */ + + if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; + + /* Chunk checksum is calculated for chunk ID (dword) and the actual + payload. */ + + real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); + + /* The in-file checksum is the last dword past the chunk data. */ + + file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); + + /* If the checksums do not match, we need to fix the file. */ + + if (real_cksum != file_cksum) { + + /* First modification? Make a copy of the input buffer. Round size + up to 4 kB to minimize the number of reallocs needed. */ + + if (new_buf == in_buf) { + + if (len <= data->size) { + + new_buf = data->buf; + + } else { + + new_buf = realloc(data->buf, UP4K(len)); + if (!new_buf) { + + *out_buf = in_buf; + return len; + + } + + data->buf = new_buf; + data->size = UP4K(len); + memcpy(new_buf, in_buf, len); + + } + + } + + *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; + + } + + /* Skip the entire chunk and move to the next one. */ + + pos += 12 + chunk_len; + + } + + *out_buf = new_buf; + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/custom_mutators/examples/simple-chunk-replace.py b/custom_mutators/examples/simple-chunk-replace.py new file mode 100644 index 00000000..c57218dd --- /dev/null +++ b/custom_mutators/examples/simple-chunk-replace.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Simple Chunk Cross-Over Replacement Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +import random + + +def init(seed): + """ + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + """ + # Seed our RNG + random.seed(seed) + + +def fuzz(buf, add_buf, max_size): + """ + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + """ + # Make a copy of our input buffer for returning + ret = bytearray(buf) + + # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) + fragment_len = random.randint(1, min(len(add_buf), 32)) + + # Determine a random source index where to take the data chunk from + rand_src_idx = random.randint(0, len(add_buf) - fragment_len) + + # Determine a random destination index where to put the data chunk + rand_dst_idx = random.randint(0, len(buf)) + + # Make the chunk replacement + ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[ + rand_src_idx : rand_src_idx + fragment_len + ] + + # Return data + return ret diff --git a/custom_mutators/examples/simple_example.c b/custom_mutators/examples/simple_example.c new file mode 100644 index 00000000..d888ec1f --- /dev/null +++ b/custom_mutators/examples/simple_example.c @@ -0,0 +1,74 @@ +// This simple example just creates random buffer <= 100 filled with 'A' +// needs -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#ifndef _FIXED_CHAR + #define _FIXED_CHAR 0x41 +#endif + +typedef struct my_mutator { + + afl_t *afl; + + // Reused buffers: + BUF_VAR(u8, fuzz); + +} my_mutator_t; + +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + int size = (rand() % 100) + 1; + if (size > max_size) size = max_size; + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + memset(mutated_out, _FIXED_CHAR, size); + + *out_buf = mutated_out; + return size; + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->fuzz_buf); + free(data); + +} + diff --git a/custom_mutators/examples/wrapper_afl_min.py b/custom_mutators/examples/wrapper_afl_min.py new file mode 100644 index 00000000..5cd60031 --- /dev/null +++ b/custom_mutators/examples/wrapper_afl_min.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +from XmlMutatorMin import XmlMutatorMin + +# Default settings (production mode) + +__mutator__ = None +__seed__ = "RANDOM" +__log__ = False +__log_file__ = "wrapper.log" + + +# AFL functions +def log(text): + """ + Logger + """ + + global __seed__ + global __log__ + global __log_file__ + + if __log__: + with open(__log_file__, "a") as logf: + logf.write("[%s] %s\n" % (__seed__, text)) + + +def init(seed): + """ + Called once when AFL starts up. Seed is used to identify the AFL instance in log files + """ + + global __mutator__ + global __seed__ + + # Get the seed + __seed__ = seed + + # Create a global mutation class + try: + __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) + log("init(): Mutator created") + except RuntimeError as e: + log("init(): Can't create mutator: %s" % e.message) + + +def fuzz(buf, add_buf, max_size): + """ + Called for each fuzzing iteration. + """ + + global __mutator__ + + # Do we have a working mutator object? + if __mutator__ is None: + log("fuzz(): Can't fuzz, no mutator available") + return buf + + # Try to use the AFL buffer + via_buffer = True + + # Interpret the AFL buffer (an array of bytes) as a string + if via_buffer: + try: + buf_str = str(buf) + log("fuzz(): AFL buffer converted to a string") + except Exception: + via_buffer = False + log("fuzz(): Can't convert AFL buffer to a string") + + # Load XML from the AFL string + if via_buffer: + try: + __mutator__.init_from_string(buf_str) + log( + "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" + % len(buf_str) + ) + except Exception: + via_buffer = False + log("fuzz(): Can't initialize mutator with AFL buffer") + + # If init from AFL buffer wasn't succesful + if not via_buffer: + log("fuzz(): Returning unmodified AFL buffer") + return buf + + # Sucessful initialization -> mutate + try: + __mutator__.mutate(max=5) + log("fuzz(): Input mutated") + except Exception: + log("fuzz(): Can't mutate input => returning buf") + return buf + + # Convert mutated data to a array of bytes + try: + data = bytearray(__mutator__.save_to_string()) + log("fuzz(): Mutated data converted as bytes") + except Exception: + log("fuzz(): Can't convert mutated data to bytes => returning buf") + return buf + + # Everything went fine, returning mutated content + log("fuzz(): Returning %d bytes" % len(data)) + return data + + +# Main (for debug) +if __name__ == "__main__": + + __log__ = True + __log_file__ = "/dev/stdout" + __seed__ = "RANDOM" + + init(__seed__) + + in_1 = bytearray( + "ffffzzzzzzzzzzzz" + ) + in_2 = bytearray("") + out = fuzz(in_1, in_2) + print(out) diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 62e01f83..9d5381e8 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -285,8 +285,8 @@ afl-fuzz /path/to/program ## 4) Example -Please see [example.c](../utils/custom_mutators/example.c) and -[example.py](../utils/custom_mutators/example.py) +Please see [example.c](../custom_mutators/examples/example.c) and +[example.py](../custom_mutators/examples/example.py) ## 5) Other Resources diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index 50ad75d4..f9ac1c53 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -83,5 +83,5 @@ 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 utils/custom_mutators/ for more. +See `afl_custom_post_process` in custom_mutators/examples/examples.c for more. diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 4aa2133e..38cb5ba6 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -190,8 +190,8 @@ handlers of the target. ## 13) Gotchas, feedback, bugs -If you need to fix up checksums or do other cleanup on mutated test cases, see -utils/custom_mutators/ for a viable solution. +If you need to fix up checksums or do other cleanups on mutated test cases, see +`afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution. Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate the "shadow VM" trick employed by the sanitizers and will probably just diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index bae4220f..a5d666ff 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.sh @@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { } } # Compile the custom mutator - cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 - cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ./libexamplemutator.so && { # Create input directory mkdir -p in diff --git a/utils/custom_mutators/Makefile b/utils/custom_mutators/Makefile deleted file mode 100644 index 9849f3f4..00000000 --- a/utils/custom_mutators/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: libexamplemutator.so - -libexamplemutator.so: - $(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so - -clean: - rm -rf libexamplemutator.so diff --git a/utils/custom_mutators/README.md b/utils/custom_mutators/README.md deleted file mode 100644 index 655f7a5e..00000000 --- a/utils/custom_mutators/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Examples for the custom mutator - -These are example and helper files for the custom mutator feature. -See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information - -Note that if you compile with python3.7 you must use python3 scripts, and if -you use python2.7 to compile python2 scripts! - -simple_example.c - most simplest example. generates a random sized buffer - filled with 'A' - -example.c - this is a simple example written in C and should be compiled to a - shared library. Use make to compile it and produce libexamplemutator.so - -example.py - this is the template you can use, the functions are there but they - are empty - -post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF - -post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG - -simple-chunk-replace.py - this is a simple example where chunks are replaced - -common.py - this can be used for common functions and helpers. - the examples do not use this though. But you can :) - -wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py - -XmlMutatorMin.py - module for XML mutation - -custom_mutator_helpers.h is an header that defines some helper routines -like surgical_havoc_mutate() that allow to perform a randomly chosen -mutation from a subset of the havoc mutations. -If you do so, you have to specify -I /path/to/AFLplusplus/include when -compiling. diff --git a/utils/custom_mutators/XmlMutatorMin.py b/utils/custom_mutators/XmlMutatorMin.py deleted file mode 100644 index 3e6cd0ff..00000000 --- a/utils/custom_mutators/XmlMutatorMin.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/python - -""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """ - -from __future__ import print_function -from copy import deepcopy -from lxml import etree as ET -import random, re, io - - -########################### -# The XmlMutatorMin class # -########################### - - -class XmlMutatorMin: - - """ - Optionals parameters: - seed Seed used by the PRNG (default: "RANDOM") - verbose Verbosity (default: False) - """ - - def __init__(self, seed="RANDOM", verbose=False): - - """ Initialize seed, database and mutators """ - - # Verbosity - self.verbose = verbose - - # Initialize PRNG - self.seed = str(seed) - if self.seed == "RANDOM": - random.seed() - else: - if self.verbose: - print("Static seed '%s'" % self.seed) - random.seed(self.seed) - - # Initialize input and output documents - self.input_tree = None - self.tree = None - - # High-level mutators (no database needed) - hl_mutators_delete = [ - "del_node_and_children", - "del_node_but_children", - "del_attribute", - "del_content", - ] # Delete items - hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values - - # Exposed mutators - self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete - - def __parse_xml(self, xml): - - """ Parse an XML string. Basic wrapper around lxml.parse() """ - - try: - # Function parse() takes care of comments / DTD / processing instructions / ... - tree = ET.parse(io.BytesIO(xml)) - except ET.ParseError: - raise RuntimeError("XML isn't well-formed!") - except LookupError as e: - raise RuntimeError(e) - - # Return a document wrapper - return tree - - def __exec_among(self, module, functions, min_times, max_times): - - """ Randomly execute $functions between $min and $max times """ - - for i in xrange(random.randint(min_times, max_times)): - # Function names are mangled because they are "private" - getattr(module, "_XmlMutatorMin__" + random.choice(functions))() - - def __serialize_xml(self, tree): - - """ Serialize a XML document. Basic wrapper around lxml.tostring() """ - - return ET.tostring( - tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding - ) - - def __ver(self, version): - - """ Helper for displaying lxml version numbers """ - - return ".".join(map(str, version)) - - def reset(self): - - """ Reset the mutator """ - - self.tree = deepcopy(self.input_tree) - - def init_from_string(self, input_string): - - """ Initialize the mutator from a XML string """ - - # Get a pointer to the top-element - self.input_tree = self.__parse_xml(input_string) - - # Get a working copy - self.tree = deepcopy(self.input_tree) - - def save_to_string(self): - - """ Return the current XML document as UTF-8 string """ - - # Return a text version of the tree - return self.__serialize_xml(self.tree) - - def __pick_element(self, exclude_root_node=False): - - """ Pick a random element from the current document """ - - # Get a list of all elements, but nodes like PI and comments - elems = list(self.tree.getroot().iter(tag=ET.Element)) - - # Is the root node excluded? - if exclude_root_node: - start = 1 - else: - start = 0 - - # Pick a random element - try: - elem_id = random.randint(start, len(elems) - 1) - elem = elems[elem_id] - except ValueError: - # Should only occurs if "exclude_root_node = True" - return (None, None) - - return (elem_id, elem) - - def __fuzz_attribute(self): - - """ Fuzz (part of) an attribute value """ - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't replace!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # We have the attribute to modify - # Get its value - attrib_value = rand_elem.get(rand_attrib) - # print("- Value: " + attrib_value) - - # Should we work on the whole value? - func_call = "(?P[a-zA-Z:\-]+)\((?P.*?)\)" - p = re.compile(func_call) - l = p.findall(attrib_value) - if random.choice((True, False)) and l: - # Randomly pick one the function calls - (func, args) = random.choice(l) - # Split by "," and randomly pick one of the arguments - value = random.choice(args.split(",")) - # Remove superfluous characters - unclean_value = value - value = value.strip(" ").strip("'") - # print("Selected argument: [%s]" % value) - else: - value = attrib_value - - # For each type, define some possible replacement values - choices_number = ( - "0", - "11111", - "-128", - "2", - "-1", - "1/3", - "42/0", - "1094861636 idiv 1.0", - "-1123329771506872 idiv 3.8", - "17=$numericRTF", - str(3 + random.randrange(0, 100)), - ) - - choices_letter = ( - "P" * (25 * random.randrange(1, 100)), - "%s%s%s%s%s%s", - "foobar", - ) - - choices_alnum = ( - "Abc123", - "020F0302020204030204", - "020F0302020204030204" * (random.randrange(5, 20)), - ) - - # Fuzz the value - if random.choice((True, False)) and value == "": - - # Empty - new_value = value - - elif random.choice((True, False)) and value.isdigit(): - - # Numbers - new_value = random.choice(choices_number) - - elif random.choice((True, False)) and value.isalpha(): - - # Letters - new_value = random.choice(choices_letter) - - elif random.choice((True, False)) and value.isalnum(): - - # Alphanumeric - new_value = random.choice(choices_alnum) - - else: - - # Default type - new_value = random.choice(choices_alnum + choices_letter + choices_number) - - # If we worked on a substring, apply changes to the whole string - if value != attrib_value: - # No ' around empty values - if new_value != "" and value != "": - new_value = "'" + new_value + "'" - # Apply changes - new_value = attrib_value.replace(unclean_value, new_value) - - # Log something - if self.verbose: - print( - "Fuzzing attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Modify the attribute - rand_elem.set(rand_attrib, new_value.decode("utf-8")) - - def __del_node_and_children(self): - - """High-level minimizing mutator - Delete a random node and its children (i.e. delete a random tree)""" - - self.__del_node(True) - - def __del_node_but_children(self): - - """High-level minimizing mutator - Delete a random node but its children (i.e. link them to the parent of the deleted node)""" - - self.__del_node(False) - - def __del_node(self, delete_children): - - """ Called by the __del_node_* mutators """ - - # Select a node to modify (but the root one) - (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True) - - # If the document includes only a top-level element - # Then we can't pick a element (given that "exclude_root_node = True") - - # Is the document deep enough? - if rand_elem is None: - if self.verbose: - print("Can't delete a node: document not deep enough!") - return - - # Log something - if self.verbose: - but_or_and = "and" if delete_children else "but" - print( - "Deleting tag #%i '%s' %s its children" - % (rand_elem_id, rand_elem.tag, but_or_and) - ) - - if delete_children is False: - # Link children of the random (soon to be deleted) node to its parent - for child in rand_elem: - rand_elem.getparent().append(child) - - # Remove the node - rand_elem.getparent().remove(rand_elem) - - def __del_content(self): - - """High-level minimizing mutator - Delete the attributes and children of a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Log something - if self.verbose: - print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) - - # Reset the node - rand_elem.clear() - - def __del_attribute(self): - - """High-level minimizing mutator - Delete a random attribute from a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't delete!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # Log something - if self.verbose: - print( - "Deleting attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Delete the attribute - rand_elem.attrib.pop(rand_attrib) - - def mutate(self, min=1, max=5): - - """ Execute some high-level mutators between $min and $max times, then some medium-level ones """ - - # High-level mutation - self.__exec_among(self, self.hl_mutators_all, min, max) diff --git a/utils/custom_mutators/common.py b/utils/custom_mutators/common.py deleted file mode 100644 index 44a5056a..00000000 --- a/utils/custom_mutators/common.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Module containing functions shared between multiple AFL modules - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -from __future__ import print_function -import random -import os -import re - - -def randel(l): - if not l: - return None - return l[random.randint(0, len(l) - 1)] - - -def randel_pop(l): - if not l: - return None - return l.pop(random.randint(0, len(l) - 1)) - - -def write_exc_example(data, exc): - exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc)) - - if not os.path.exists(exc_name): - with open(exc_name, "w") as f: - f.write(data) diff --git a/utils/custom_mutators/custom_mutator_helpers.h b/utils/custom_mutators/custom_mutator_helpers.h deleted file mode 100644 index 62e6efba..00000000 --- a/utils/custom_mutators/custom_mutator_helpers.h +++ /dev/null @@ -1,342 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include - -#define INITIAL_GROWTH_SIZE (64) - -#define RAND_BELOW(limit) (rand() % (limit)) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this fills in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -typedef struct { - -} afl_t; - -static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { - - static s8 interesting_8[] = {INTERESTING_8}; - static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; - static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - - switch (RAND_BELOW(12)) { - - case 0: { - - /* Flip a single bit somewhere. Spooky! */ - - s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); - - out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); - - break; - - } - - case 1: { - - /* Set byte to interesting value. */ - - u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; - out_buf[(RAND_BELOW(end - begin) + begin)] = val; - - break; - - } - - case 2: { - - /* Set word to interesting value, randomly choosing endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u16 *)(out_buf + byte_idx) = - interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; - break; - case 1: - *(u16 *)(out_buf + byte_idx) = - SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); - break; - - } - - break; - - } - - case 3: { - - /* Set dword to interesting value, randomly choosing endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u32 *)(out_buf + byte_idx) = - interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u32 *)(out_buf + byte_idx) = - SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 4: { - - /* Set qword to interesting value, randomly choosing endian. */ - - if (end - begin < 8) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 7) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u64 *)(out_buf + byte_idx) = - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u64 *)(out_buf + byte_idx) = SWAP64( - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 5: { - - /* Randomly subtract from byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 6: { - - /* Randomly add to byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 7: { - - /* Randomly subtract from word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 8: { - - /* Randomly add to word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 9: { - - /* Randomly subtract from dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 10: { - - /* Randomly add to dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 11: { - - /* Just set a random byte to a random value. Because, - why not. We use XOR with 1-255 to eliminate the - possibility of a no-op. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); - - break; - - } - - } - -} - -/* This function calculates the next power of 2 greater or equal its argument. - @return The rounded up power of 2 (if no overflow) or 0 on overflow. -*/ -static inline size_t next_pow2(size_t in) { - - if (in == 0 || in > (size_t)-1) - return 0; /* avoid undefined behaviour under-/overflow */ - size_t out = in - 1; - out |= out >> 1; - out |= out >> 2; - out |= out >> 4; - out |= out >> 8; - out |= out >> 16; - return out + 1; - -} - -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) return *buf; - - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); - - /* handle overflow */ - if (!next_size) { next_size = size_needed; } - - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; - - return *buf; - -} - -/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { - - void * scratch_buf = *buf1; - size_t scratch_size = *size1; - *buf1 = *buf2; - *size1 = *size2; - *buf2 = scratch_buf; - *size2 = scratch_size; - -} - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/utils/custom_mutators/example.c b/utils/custom_mutators/example.c deleted file mode 100644 index 23add128..00000000 --- a/utils/custom_mutators/example.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - New Custom Mutator for AFL++ - Written by Khaled Yakdan - Andrea Fioraldi - Shengtuo Hu - Dominik Maier -*/ - -// You need to use -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#define DATA_SIZE (100) - -static const char *commands[] = { - - "GET", - "PUT", - "DEL", - -}; - -typedef struct my_mutator { - - afl_t *afl; - - // any additional data here! - size_t trim_size_current; - int trimmming_steps; - int cur_step; - - // Reused buffers: - BUF_VAR(u8, fuzz); - BUF_VAR(u8, data); - BUF_VAR(u8, havoc); - BUF_VAR(u8, trim); - BUF_VAR(u8, post_process); - -} my_mutator_t; - -/** - * Initialize this custom mutator - * - * @param[in] afl a pointer to the internal state object. Can be ignored for - * now. - * @param[in] seed A seed for this mutator - the same seed should always mutate - * in the same way. - * @return Pointer to the data object this custom mutator instance should use. - * There may be multiple instances of this mutator in one afl-fuzz run! - * Return NULL on error. - */ -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); // needed also by surgical_havoc_mutate() - - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -/** - * Perform custom mutations on a given input - * - * (Optional for now. Required in the future) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to input data to be mutated - * @param[in] buf_size Size of input data - * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on - * error. - * @param[in] add_buf Buffer containing the additional test case - * @param[in] add_buf_size Size of the additional test case - * @param[in] max_size Maximum size of the mutated output. The mutation must not - * produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - // Make sure that the packet size does not exceed the maximum size expected by - // the fuzzer - size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; - - // maybe_grow is optimized to be quick for reused buffers. - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - // Randomly select a command string to add as a header to the packet - memcpy(mutated_out, commands[rand() % 3], 3); - - // Mutate the payload of the packet - int i; - for (i = 0; i < 8; ++i) { - - // Randomly perform one of the (no len modification) havoc mutations - surgical_havoc_mutate(mutated_out, 3, mutated_size); - - } - - *out_buf = mutated_out; - return mutated_size; - -} - -/** - * A post-processing function to use right before AFL writes the test case to - * disk in order to execute the target. - * - * (Optional) If this functionality is not needed, simply don't define this - * function. - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Buffer containing the test case to be executed - * @param[in] buf_size Size of the test case - * @param[out] out_buf Pointer to the buffer containing the test case after - * processing. External library should allocate memory for out_buf. - * The buf pointer may be reused (up to the given buf_size); - * @return Size of the output buffer after processing or the needed amount. - * A return of 0 indicates an error. - */ -size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, - size_t buf_size, uint8_t **out_buf) { - - uint8_t *post_process_buf = - maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); - if (!post_process_buf) { - - perror("custom mutator realloc failed."); - *out_buf = NULL; - return 0; - - } - - memcpy(post_process_buf + 5, buf, buf_size); - post_process_buf[0] = 'A'; - post_process_buf[1] = 'F'; - post_process_buf[2] = 'L'; - post_process_buf[3] = '+'; - post_process_buf[4] = '+'; - - *out_buf = post_process_buf; - - return buf_size + 5; - -} - -/** - * This method is called at the start of each trimming operation and receives - * the initial buffer. It should return the amount of iteration steps possible - * on this input (e.g. if your input has n elements and you want to remove - * them one by one, return n, if you do a binary search, return log(n), - * and so on...). - * - * If your trimming algorithm doesn't allow you to determine the amount of - * (remaining) steps easily (esp. while running), then you can alternatively - * return 1 here and always return 0 in post_trim until you are finished and - * no steps remain. In that case, returning 1 in post_trim will end the - * trimming routine. The whole current index/max iterations stuff is only used - * to show progress. - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param buf Buffer containing the test case - * @param buf_size Size of the test case - * @return The amount of possible iteration steps to trim the input. - * negative on error. - */ -int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, - size_t buf_size) { - - // We simply trim once - data->trimmming_steps = 1; - - data->cur_step = 0; - - if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { - - perror("init_trim grow"); - return -1; - - } - - memcpy(data->trim_buf, buf, buf_size); - - data->trim_size_current = buf_size; - - return data->trimmming_steps; - -} - -/** - * This method is called for each trimming operation. It doesn't have any - * arguments because we already have the initial buffer from init_trim and we - * can memorize the current state in *data. This can also save - * reparsing steps for each iteration. It should return the trimmed input - * buffer, where the returned data must not exceed the initial input data in - * length. Returning anything that is larger than the original data (passed - * to init_trim) will result in a fatal abort of AFLFuzz. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[out] out_buf Pointer to the buffer containing the trimmed test case. - * External library should allocate memory for out_buf. - * AFL++ will not release the memory after saving the test case. - * Keep a ref in *data. - * *out_buf = NULL is treated as error. - * @return Pointer to the size of the trimmed test case - */ -size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { - - *out_buf = data->trim_buf; - - // Remove the last byte of the trimming input - return data->trim_size_current - 1; - -} - -/** - * This method is called after each trim operation to inform you if your - * trimming step was successful or not (in terms of coverage). If you receive - * a failure here, you should reset your input to the last known good state. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param success Indicates if the last trim operation was successful. - * @return The next trim iteration index (from 0 to the maximum amount of - * steps returned in init_trim). negative ret on failure. - */ -int32_t afl_custom_post_trim(my_mutator_t *data, int success) { - - if (success) { - - ++data->cur_step; - return data->cur_step; - - } - - return data->trimmming_steps; - -} - -/** - * Perform a single custom mutation on a given input. - * This mutation is stacked with the other muatations in havoc. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to the input data to be mutated and the mutated - * output - * @param[in] buf_size Size of input data - * @param[out] out_buf The output buffer. buf can be reused, if the content - * fits. *out_buf = NULL is treated as error. - * @param[in] max_size Maximum size of the mutated output. The mutation must - * not produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, - u8 **out_buf, size_t max_size) { - - if (buf_size == 0) { - - *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); - if (!*out_buf) { - - perror("custom havoc: maybe_grow"); - return 0; - - } - - **out_buf = rand() % 256; - buf_size = 1; - - } else { - - // We reuse buf here. It's legal and faster. - *out_buf = buf; - - } - - size_t victim = rand() % buf_size; - (*out_buf)[victim] += rand() % 10; - - return buf_size; - -} - -/** - * Return the probability (in percentage) that afl_custom_havoc_mutation - * is called in havoc. By default it is 6 %. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @return The probability (0-100). - */ -uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { - - return 5; // 5 % - -} - -/** - * Determine whether the fuzzer should fuzz the queue entry or not. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param filename File name of the test case in the queue entry - * @return Return True(1) if the fuzzer will fuzz the queue entry, and - * False(0) otherwise. - */ -uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { - - return 1; - -} - -/** - * Allow for additional analysis (e.g. calling a different tool that does a - * different kind of coverage and saves this for the custom mutator). - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param filename_new_queue File name of the new queue entry - * @param filename_orig_queue File name of the original queue entry - */ -void afl_custom_queue_new_entry(my_mutator_t * data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { - - /* Additional analysis on the original or new test case */ - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->post_process_buf); - free(data->havoc_buf); - free(data->data_buf); - free(data->fuzz_buf); - free(data->trim_buf); - free(data); - -} - diff --git a/utils/custom_mutators/example.py b/utils/custom_mutators/example.py deleted file mode 100644 index 3a6d22e4..00000000 --- a/utils/custom_mutators/example.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Example Python Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -import random - - -COMMANDS = [ - b"GET", - b"PUT", - b"DEL", - b"AAAAAAAAAAAAAAAAA", -] - - -def init(seed): - """ - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - """ - random.seed(seed) - - -def deinit(): - pass - - -def fuzz(buf, add_buf, max_size): - """ - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - """ - ret = bytearray(100) - - ret[:3] = random.choice(COMMANDS) - - return ret - - -# Uncomment and implement the following methods if you want to use a custom -# trimming algorithm. See also the documentation for a better API description. - -# def init_trim(buf): -# ''' -# Called per trimming iteration. -# -# @type buf: bytearray -# @param buf: The buffer that should be trimmed. -# -# @rtype: int -# @return: The maximum number of trimming steps. -# ''' -# global ... -# -# # Initialize global variables -# -# # Figure out how many trimming steps are possible. -# # If this is not possible for your trimming, you can -# # return 1 instead and always return 0 in post_trim -# # until you are done (then you return 1). -# -# return steps -# -# def trim(): -# ''' -# Called per trimming iteration. -# -# @rtype: bytearray -# @return: A new bytearray containing the trimmed data. -# ''' -# global ... -# -# # Implement the actual trimming here -# -# return bytearray(...) -# -# def post_trim(success): -# ''' -# Called after each trimming operation. -# -# @type success: bool -# @param success: Indicates if the last trim operation was successful. -# -# @rtype: int -# @return: The next trim index (0 to max number of steps) where max -# number of steps indicates the trimming is done. -# ''' -# global ... -# -# if not success: -# # Restore last known successful input, determine next index -# else: -# # Just determine the next index, based on what was successfully -# # removed in the last step -# -# return next_index -# -# def post_process(buf): -# ''' -# Called just before the execution to write the test case in the format -# expected by the target -# -# @type buf: bytearray -# @param buf: The buffer containing the test case to be executed -# -# @rtype: bytearray -# @return: The buffer containing the test case after -# ''' -# return buf -# -# def havoc_mutation(buf, max_size): -# ''' -# Perform a single custom mutation on a given input. -# -# @type buf: bytearray -# @param buf: The buffer that should be mutated. -# -# @type max_size: int -# @param max_size: Maximum size of the mutated output. The mutation must not -# produce data larger than max_size. -# -# @rtype: bytearray -# @return: A new bytearray containing the mutated data -# ''' -# return mutated_buf -# -# def havoc_mutation_probability(): -# ''' -# Called for each `havoc_mutation`. Return the probability (in percentage) -# that `havoc_mutation` is called in havoc. Be default it is 6%. -# -# @rtype: int -# @return: The probability (0-100) -# ''' -# return prob -# -# def queue_get(filename): -# ''' -# Called at the beginning of each fuzz iteration to determine whether the -# test case should be fuzzed -# -# @type filename: str -# @param filename: File name of the test case in the current queue entry -# -# @rtype: bool -# @return: Return True if the custom mutator decides to fuzz the test case, -# and False otherwise -# ''' -# return True -# -# def queue_new_entry(filename_new_queue, filename_orig_queue): -# ''' -# Called after adding a new test case to the queue -# -# @type filename_new_queue: str -# @param filename_new_queue: File name of the new queue entry -# -# @type filename_orig_queue: str -# @param filename_orig_queue: File name of the original queue entry -# ''' -# pass diff --git a/utils/custom_mutators/post_library_gif.so.c b/utils/custom_mutators/post_library_gif.so.c deleted file mode 100644 index ac10f409..00000000 --- a/utils/custom_mutators/post_library_gif.so.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - american fuzzy lop++ - postprocessor library example - -------------------------------------------------- - - Originally written by Michal Zalewski - Edited by Dominik Maier, 2020 - - Copyright 2015 Google Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - Postprocessor libraries can be passed to afl-fuzz to perform final cleanup - of any mutated test cases - for example, to fix up checksums in PNG files. - - Please heed the following warnings: - - 1) In almost all cases, it is more productive to comment out checksum logic - in the targeted binary (as shown in ../libpng_no_checksum/). One possible - exception is the process of fuzzing binary-only software in QEMU mode. - - 2) The use of postprocessors for anything other than checksums is - questionable and may cause more harm than good. AFL is normally pretty good - about dealing with length fields, magic values, etc. - - 3) Postprocessors that do anything non-trivial must be extremely robust to - gracefully handle malformed data and other error conditions - otherwise, - they will crash and take afl-fuzz down with them. Be wary of reading past - *len and of integer overflows when calculating file offsets. - - In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, - honestly know what you're doing =) - - With that out of the way: the postprocessor library is passed to afl-fuzz - via AFL_POST_LIBRARY. The library must be compiled with: - - gcc -shared -Wall -O3 post_library.so.c -o post_library.so - - AFL will call the afl_custom_post_process() function for every mutated output - buffer. From there, you have three choices: - - 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` - and return the original `len`. - - 2) If you want to skip this test case altogether and have AFL generate a - new one, return 0 or set `*out_buf = NULL`. - Use this sparingly - it's faster than running the target program - with patently useless inputs, but still wastes CPU time. - - 3) If you want to modify the test case, allocate an appropriately-sized - buffer, move the data into that buffer, make the necessary changes, and - then return the new pointer as out_buf. Return an appropriate len - afterwards. - - Note that the buffer will *not* be freed for you. To avoid memory leaks, - you need to free it or reuse it on subsequent calls (as shown below). - - *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - - Aight. The example below shows a simple postprocessor that tries to make - sure that all input files start with "GIF89a". - - PS. If you don't like C, you can try out the unix-based wrapper from - Ben Nagy instead: https://github.com/bnagy/aflfix - - */ - -#include -#include -#include - -/* Header that must be present at the beginning of every test case: */ - -#define HEADER "GIF89a" - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -/* The actual postprocessor routine called by afl-fuzz: */ - -size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, - unsigned int len, unsigned char **out_buf) { - - /* Skip execution altogether for buffers shorter than 6 bytes (just to - show how it's done). We can trust len to be sane. */ - - if (len < strlen(HEADER)) return 0; - - /* Do nothing for buffers that already start with the expected header. */ - - if (!memcmp(in_buf, HEADER, strlen(HEADER))) { - - *out_buf = in_buf; - return len; - - } - - /* Allocate memory for new buffer, reusing previous allocation if - possible. */ - - *out_buf = realloc(data->buf, len); - - /* If we're out of memory, the most graceful thing to do is to return the - original buffer and give up on modifying it. Let AFL handle OOM on its - own later on. */ - - if (!*out_buf) { - - *out_buf = in_buf; - return len; - - } - - /* Copy the original data to the new location. */ - - memcpy(*out_buf, in_buf, len); - - /* Insert the new header. */ - - memcpy(*out_buf, HEADER, strlen(HEADER)); - - /* Return the new len. It hasn't changed, so it's just len. */ - - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/utils/custom_mutators/post_library_png.so.c b/utils/custom_mutators/post_library_png.so.c deleted file mode 100644 index 941f7e55..00000000 --- a/utils/custom_mutators/post_library_png.so.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - american fuzzy lop++ - postprocessor for PNG - ------------------------------------------ - - Originally written by Michal Zalewski - - Copyright 2015 Google Inc. All rights reserved. - Adapted to the new API, 2020 by Dominik Maier - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - See post_library.so.c for a general discussion of how to implement - postprocessors. This specific postprocessor attempts to fix up PNG - checksums, providing a slightly more complicated example than found - in post_library.so.c. - - Compile with: - - gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz - - */ - -#include -#include -#include -#include -#include - -#include - -/* A macro to round an integer up to 4 kB. */ - -#define UP4K(_i) ((((_i) >> 12) + 1) << 12) - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, - unsigned int len, - const unsigned char **out_buf) { - - unsigned char *new_buf = (unsigned char *)in_buf; - unsigned int pos = 8; - - /* Don't do anything if there's not enough room for the PNG header - (8 bytes). */ - - if (len < 8) { - - *out_buf = in_buf; - return len; - - } - - /* Minimum size of a zero-length PNG chunk is 12 bytes; if we - don't have that, we can bail out. */ - - while (pos + 12 <= len) { - - unsigned int chunk_len, real_cksum, file_cksum; - - /* Chunk length is the first big-endian dword in the chunk. */ - - chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); - - /* Bail out if chunk size is too big or goes past EOF. */ - - if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; - - /* Chunk checksum is calculated for chunk ID (dword) and the actual - payload. */ - - real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); - - /* The in-file checksum is the last dword past the chunk data. */ - - file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); - - /* If the checksums do not match, we need to fix the file. */ - - if (real_cksum != file_cksum) { - - /* First modification? Make a copy of the input buffer. Round size - up to 4 kB to minimize the number of reallocs needed. */ - - if (new_buf == in_buf) { - - if (len <= data->size) { - - new_buf = data->buf; - - } else { - - new_buf = realloc(data->buf, UP4K(len)); - if (!new_buf) { - - *out_buf = in_buf; - return len; - - } - - data->buf = new_buf; - data->size = UP4K(len); - memcpy(new_buf, in_buf, len); - - } - - } - - *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; - - } - - /* Skip the entire chunk and move to the next one. */ - - pos += 12 + chunk_len; - - } - - *out_buf = new_buf; - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/utils/custom_mutators/simple-chunk-replace.py b/utils/custom_mutators/simple-chunk-replace.py deleted file mode 100644 index c57218dd..00000000 --- a/utils/custom_mutators/simple-chunk-replace.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Simple Chunk Cross-Over Replacement Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -import random - - -def init(seed): - """ - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - """ - # Seed our RNG - random.seed(seed) - - -def fuzz(buf, add_buf, max_size): - """ - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - """ - # Make a copy of our input buffer for returning - ret = bytearray(buf) - - # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) - fragment_len = random.randint(1, min(len(add_buf), 32)) - - # Determine a random source index where to take the data chunk from - rand_src_idx = random.randint(0, len(add_buf) - fragment_len) - - # Determine a random destination index where to put the data chunk - rand_dst_idx = random.randint(0, len(buf)) - - # Make the chunk replacement - ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[ - rand_src_idx : rand_src_idx + fragment_len - ] - - # Return data - return ret diff --git a/utils/custom_mutators/simple_example.c b/utils/custom_mutators/simple_example.c deleted file mode 100644 index d888ec1f..00000000 --- a/utils/custom_mutators/simple_example.c +++ /dev/null @@ -1,74 +0,0 @@ -// This simple example just creates random buffer <= 100 filled with 'A' -// needs -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#ifndef _FIXED_CHAR - #define _FIXED_CHAR 0x41 -#endif - -typedef struct my_mutator { - - afl_t *afl; - - // Reused buffers: - BUF_VAR(u8, fuzz); - -} my_mutator_t; - -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - int size = (rand() % 100) + 1; - if (size > max_size) size = max_size; - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - memset(mutated_out, _FIXED_CHAR, size); - - *out_buf = mutated_out; - return size; - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->fuzz_buf); - free(data); - -} - diff --git a/utils/custom_mutators/wrapper_afl_min.py b/utils/custom_mutators/wrapper_afl_min.py deleted file mode 100644 index 5cd60031..00000000 --- a/utils/custom_mutators/wrapper_afl_min.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python - -from XmlMutatorMin import XmlMutatorMin - -# Default settings (production mode) - -__mutator__ = None -__seed__ = "RANDOM" -__log__ = False -__log_file__ = "wrapper.log" - - -# AFL functions -def log(text): - """ - Logger - """ - - global __seed__ - global __log__ - global __log_file__ - - if __log__: - with open(__log_file__, "a") as logf: - logf.write("[%s] %s\n" % (__seed__, text)) - - -def init(seed): - """ - Called once when AFL starts up. Seed is used to identify the AFL instance in log files - """ - - global __mutator__ - global __seed__ - - # Get the seed - __seed__ = seed - - # Create a global mutation class - try: - __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) - log("init(): Mutator created") - except RuntimeError as e: - log("init(): Can't create mutator: %s" % e.message) - - -def fuzz(buf, add_buf, max_size): - """ - Called for each fuzzing iteration. - """ - - global __mutator__ - - # Do we have a working mutator object? - if __mutator__ is None: - log("fuzz(): Can't fuzz, no mutator available") - return buf - - # Try to use the AFL buffer - via_buffer = True - - # Interpret the AFL buffer (an array of bytes) as a string - if via_buffer: - try: - buf_str = str(buf) - log("fuzz(): AFL buffer converted to a string") - except Exception: - via_buffer = False - log("fuzz(): Can't convert AFL buffer to a string") - - # Load XML from the AFL string - if via_buffer: - try: - __mutator__.init_from_string(buf_str) - log( - "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" - % len(buf_str) - ) - except Exception: - via_buffer = False - log("fuzz(): Can't initialize mutator with AFL buffer") - - # If init from AFL buffer wasn't succesful - if not via_buffer: - log("fuzz(): Returning unmodified AFL buffer") - return buf - - # Sucessful initialization -> mutate - try: - __mutator__.mutate(max=5) - log("fuzz(): Input mutated") - except Exception: - log("fuzz(): Can't mutate input => returning buf") - return buf - - # Convert mutated data to a array of bytes - try: - data = bytearray(__mutator__.save_to_string()) - log("fuzz(): Mutated data converted as bytes") - except Exception: - log("fuzz(): Can't convert mutated data to bytes => returning buf") - return buf - - # Everything went fine, returning mutated content - log("fuzz(): Returning %d bytes" % len(data)) - return data - - -# Main (for debug) -if __name__ == "__main__": - - __log__ = True - __log_file__ = "/dev/stdout" - __seed__ = "RANDOM" - - init(__seed__) - - in_1 = bytearray( - "ffffzzzzzzzzzzzz" - ) - in_2 = bytearray("") - out = fuzz(in_1, in_2) - print(out) -- cgit 1.4.1 From 4d40afe54f8365453dc3be5d1c2db5d06d42e448 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 26 Apr 2021 16:12:25 +0200 Subject: fixed example location --- docs/life_pro_tips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index f9ac1c53..13ffcea0 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -83,5 +83,5 @@ 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/examples.c for more. +See `afl_custom_post_process` in custom_mutators/examples/example.c for more. -- cgit 1.4.1 From dde0538b484df627dac14ff030dd09f55c78558e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 28 Apr 2021 10:59:34 +0200 Subject: nits --- docs/Changelog.md | 1 + qemu_mode/qemuafl | 2 +- utils/aflpp_driver/aflpp_qemu_driver_hook.c | 10 +++++----- utils/qbdi_mode/template.cpp | 2 +- utils/qemu_persistent_hook/read_into_rdi.c | 10 +++++----- 5 files changed, 13 insertions(+), 12 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 520b13b1..90a1d140 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,7 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, + it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! - create a fuzzing dictionary with the help of CodeQL thanks to @microsvuln! see utils/autodict_ql diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index d1ca56b8..d73b0336 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit d1ca56b84e78f821406eef28d836918edfc8d610 +Subproject commit d73b0336b451fd034e5f469089fb7ee96c80adf2 diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index d3dd98b0..2979fadc 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -3,12 +3,12 @@ #include #include -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -16,11 +16,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp index 888ecb58..182a014b 100755 --- a/utils/qbdi_mode/template.cpp +++ b/utils/qbdi_mode/template.cpp @@ -25,7 +25,7 @@ #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #define INC_AFL_AREA(loc) \ asm volatile( \ - "addb $1, (%0, %1, 1)\n" \ + "addb $1, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \ : /* no out */ \ : "r"(afl_area_ptr), "r"(loc) \ diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c index c1c6642f..14b2ed85 100644 --- a/utils/qemu_persistent_hook/read_into_rdi.c +++ b/utils/qemu_persistent_hook/read_into_rdi.c @@ -3,12 +3,12 @@ #include #include -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -19,11 +19,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use -- cgit 1.4.1 From c9d066038fe0bbf8e0ab0a481ca320ca1c31b1bf Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 10:27:43 +0200 Subject: fix PCGUARD, build aflpp_driver with fPIC --- docs/Changelog.md | 5 +- instrumentation/SanitizerCoverageLTO.so.cc | 15 ++-- instrumentation/SanitizerCoveragePCGUARD.so.cc | 102 +++++++++++-------------- utils/afl_proxy/afl-proxy.c | 6 ++ utils/aflpp_driver/GNUmakefile | 4 +- 5 files changed, 64 insertions(+), 68 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 90a1d140..5c0f2a9e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -32,10 +32,13 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - afl-cc: - We do not support llvm versions prior 6.0 anymore + - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode + - utils/aflpp_driver: + - aflpp_qemu_driver_hook fixed to work with qemu_mode + - aflpp_driver now compiled with -fPIC - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 6dd390e6..2f4337eb 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -60,15 +60,14 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -// static const char *const SanCovTracePCGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +// const char SanCovTracePCGuardName = // "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; static cl::opt ClCoverageLevel( "lto-coverage-level", diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 09cda9e2..8878d3b1 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -52,49 +52,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; -static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; -static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; -static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; -static const char *const SanCovTraceConstCmp1 = - "__sanitizer_cov_trace_const_cmp1"; -static const char *const SanCovTraceConstCmp2 = - "__sanitizer_cov_trace_const_cmp2"; -static const char *const SanCovTraceConstCmp4 = - "__sanitizer_cov_trace_const_cmp4"; -static const char *const SanCovTraceConstCmp8 = - "__sanitizer_cov_trace_const_cmp8"; -static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; -static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; -static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; -static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; -static const char *const SanCovModuleCtorTracePcGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -static const char *const SanCovModuleCtor8bitCountersName = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -static const char *const SanCovModuleCtorBoolFlagName = - "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -static const char *const SanCovTracePCGuardName = - "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovTracePCGuardInitName = - "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName = - "__sanitizer_cov_8bit_counters_init"; -static const char *const SanCovBoolFlagInitName = - "__sanitizer_cov_bool_flag_init"; -static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static char *skip_nozero; @@ -320,12 +310,12 @@ std::pair ModuleSanitizerCoverage::CreateSecStartEnd( Module &M, const char *Section, Type *Ty) { GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionStart(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) @@ -573,7 +563,7 @@ bool ModuleSanitizerCoverage::instrumentModule( } // True if block has successors and it dominates all of them. -static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { +bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { if (succ_begin(BB) == succ_end(BB)) return false; @@ -588,8 +578,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { } // True if block has predecessors and it postdominates all of them. -static bool isFullPostDominator(const BasicBlock * BB, - const PostDominatorTree *PDT) { +bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { if (pred_begin(BB) == pred_end(BB)) return false; @@ -603,10 +592,10 @@ static bool isFullPostDominator(const BasicBlock * BB, } -static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, - const SanitizerCoverageOptions &Options) { +bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, + const DominatorTree * DT, + const PostDominatorTree * PDT, + const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we // will never call __sanitizer_cov() for them, so counting them in @@ -636,8 +625,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // A twist here is that we treat From->To as a backedge if // * To dominates From or // * To->UniqueSuccessor dominates From -static bool IsBackEdge(BasicBlock *From, BasicBlock *To, - const DominatorTree *DT) { +bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { if (DT->dominates(To, From)) return true; if (auto Next = To->getUniqueSuccessor()) @@ -651,8 +639,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To, // // Note that Cmp pruning is controlled by the same flag as the // BB pruning. -static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, - const SanitizerCoverageOptions &Options) { +bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, + const SanitizerCoverageOptions &Options) { if (!Options.NoPrune) if (CMP->hasOneUse()) @@ -1046,7 +1034,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (IsEntryBB) { - // Keep static allocas and llvm.localescape calls in the entry block. Even + // Keep allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); @@ -1221,17 +1209,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( } -static void registerPCGUARDPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { +void registerPCGUARDPass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { auto p = new ModuleSanitizerCoverageLegacyPass(); PM.add(p); } -static RegisterStandardPasses RegisterCompTransPass( +RegisterStandardPasses RegisterCompTransPass( PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass); -static RegisterStandardPasses RegisterCompTransPass0( +RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass); diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index aa7a361a..a80d8a0b 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -70,12 +70,18 @@ static void __afl_map_shm(void) { char *id_str = getenv(SHM_ENV_VAR); char *ptr; + + /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then + uncomment the following: */ + + /* if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { u32 val = atoi(ptr); if (val > 0) __afl_map_size = val; } + */ if (__afl_map_size > MAP_SIZE) { diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index 8ac054a6..556f6420 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -7,7 +7,7 @@ ifneq "" "$(LLVM_BINDIR)" LLVM_BINDIR := $(LLVM_BINDIR)/ endif -CFLAGS := -O3 -funroll-loops -g +CFLAGS := -O3 -funroll-loops -g -fPIC all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so @@ -36,7 +36,7 @@ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o -$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + -$(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c -- cgit 1.4.1 From caf282040ffe45509b7cb37cc7c087c22bfdf034 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 11:09:49 +0200 Subject: update changelog --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 5c0f2a9e..459c2f35 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -39,6 +39,7 @@ sending a mail to . - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC + - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) -- cgit 1.4.1 From 86452cc959bd4b0d5fe6e60d0eefbc7848fe38e2 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 23:41:06 +0200 Subject: fix stdin trimming --- docs/Changelog.md | 1 + src/afl-forkserver.c | 2 +- src/afl-fuzz-run.c | 10 ++++------ utils/afl_proxy/afl-proxy.c | 23 +++++++++++++++-------- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 459c2f35..6a25865d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - fixed a bug when trimming for stdin targets - default cmplog level (-l) is now 2, better efficiency. - cmplog level 3 (-l 3) now performs redqueen on everything. use with care. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d533fd4a..a07e78b4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1090,7 +1090,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { #endif - if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { + if (likely(fsrv->use_shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a7b071a5..397d62bf 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (afl->fsrv.shmem_fuzz) { + if (likely(afl->fsrv.use_shmem_fuzz)) { if (!post_process_skipped) { @@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); - } - - else { + } else { memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); @@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, return; - } else if (afl->fsrv.out_file) { + } else if (unlikely(!afl->fsrv.use_stdin)) { if (unlikely(afl->no_unlink)) { @@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (!afl->fsrv.out_file) { + if (afl->fsrv.use_stdin) { if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index 2d8ba991..6006e238 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -195,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* report that we are starting the target */ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - if (status < 1) - return 0; - else - return status; + return status; } @@ -216,7 +213,7 @@ int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; + s32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. Any value is fine as long as it can be divided by 32. */ @@ -228,10 +225,20 @@ int main(int argc, char *argv[]) { while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ + if (len > 4) { // the minimum data size you need for the target - // ... the magic ... + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + // remove this, this is just to make afl-fuzz not complain when run + if (buf[0] == 0xff) + __afl_area_ptr[1] = 1; + else + __afl_area_ptr[2] = 2; + + } /* report the test case is done and wait for the next */ __afl_end_testcase(); -- cgit 1.4.1 From 6dc82e620b744b61ce4ad6d783f59b9c9db2827a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 6 May 2021 12:06:58 +0200 Subject: unicorn mips fixes --- docs/Changelog.md | 2 ++ unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6a25865d..0aef1e33 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -40,6 +40,8 @@ sending a mail to . - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC + - unicornafl: + - fix MIPS delay slot caching, thanks @JackGrence - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index d9ae5590..e766d2f5 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -fb2fc9f2 +f59df67375c5914321842767636a9fa6f692d5a1 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index fb2fc9f2..f59df673 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit fb2fc9f25df32f17f6b6b859e4dbd70f9a857e0c +Subproject commit f59df67375c5914321842767636a9fa6f692d5a1 -- cgit 1.4.1 From 7317a594fe5d839019d934b9c269cde146361e34 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 6 May 2021 17:14:42 +0200 Subject: unicorn fixes --- docs/Changelog.md | 2 ++ unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0aef1e33..31351a58 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -42,6 +42,8 @@ sending a mail to . - aflpp_driver now compiled with -fPIC - unicornafl: - fix MIPS delay slot caching, thanks @JackGrence + - fixed aarch64 exit address + - execution no longer stops at address 0x0 - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index e766d2f5..7677c3db 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -f59df67375c5914321842767636a9fa6f692d5a1 +3a8957fbf25b1cc9e58d59474f4a3dc0654801e3 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index f59df673..3a8957fb 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit f59df67375c5914321842767636a9fa6f692d5a1 +Subproject commit 3a8957fbf25b1cc9e58d59474f4a3dc0654801e3 -- cgit 1.4.1 From 069e61dfc67050154b649ba286552b563b27e9ba Mon Sep 17 00:00:00 2001 From: "Roman M. Iudichev" Date: Fri, 7 May 2021 18:32:17 +0300 Subject: Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. --- docs/env_variables.md | 4 ++++ include/afl-fuzz.h | 5 +++-- include/envs.h | 1 + src/afl-fuzz-state.c | 8 ++++++++ src/afl-fuzz-stats.c | 10 ++++++++++ src/afl-fuzz.c | 8 ++++++++ test/test-performance.sh | 1 + test/test-pre.sh | 1 + 8 files changed, 36 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index 0100ffac..8879db72 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,10 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were + found within a specified period of time. May be convenient for some + types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f201782a..a09d6f79 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -392,7 +392,7 @@ typedef struct afl_env_vars { *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, - *afl_persistent_record; + *afl_persistent_record, *afl_exit_on_time; } afl_env_vars_t; @@ -575,7 +575,8 @@ typedef struct afl_state { last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ - last_hang_time; /* Time for most recent hang (ms) */ + last_hang_time, /* Time for most recent hang (ms) */ + exit_on_time; /* Delay to exit if no new paths */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ subseq_tmouts; /* Number of timeouts in a row */ diff --git a/include/envs.h b/include/envs.h index cd23ca3f..9175005e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 28d3339a..73ba7a52 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; + afl->exit_on_time = 0; afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; @@ -187,6 +188,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_exit_when_done = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_TIME", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_time = + (u8 *) get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_NO_AFFINITY", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index fd9af5e4..ee8bd2da 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -574,6 +574,16 @@ void show_stats(afl_state_t *afl) { } + /* AFL_EXIT_ON_TIME. */ + + if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && + afl->afl_env.afl_exit_on_time && + (cur_ms - afl->last_path_time) > afl->exit_on_time)) { + + afl->stop_soon = 2; + + } + if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) { afl->stop_soon = 2; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8c3ba575..8de3ed6b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -204,6 +204,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" + "AFL_EXIT_ON_TIME: exit when no new paths are found within the specified time period\n" "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" @@ -1246,6 +1247,13 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_exit_on_time) { + + u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time); + afl->exit_on_time = (u64)exit_on_time * 1000; + + } + if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); diff --git a/test/test-performance.sh b/test/test-performance.sh index cd9f6caf..d61e2f2a 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -18,6 +18,7 @@ export AFL_QUIET=1 export AFL_PATH=`pwd`/.. unset AFL_EXIT_WHEN_DONE +unset AFL_EXIT_ON_TIME unset AFL_SKIP_CPUFREQ unset AFL_DEBUG unset AFL_HARDEN diff --git a/test/test-pre.sh b/test/test-pre.sh index 174f2f7f..7819da47 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -62,6 +62,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || { test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; } export AFL_EXIT_WHEN_DONE=1 +export AFL_EXIT_ON_TIME=60 export AFL_SKIP_CPUFREQ=1 export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 unset AFL_NO_X86 -- cgit 1.4.1 From 84e55e7a1bc684b2f3b52db4d6e789135af95d13 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 10 May 2021 10:38:31 +0200 Subject: arch linux and mac os support for afl-system-config --- afl-system-config | 10 +++++++--- docs/Changelog.md | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/afl-system-config b/afl-system-config index 5ad9d937..e08871ac 100755 --- a/afl-system-config +++ b/afl-system-config @@ -22,7 +22,10 @@ if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then fi if [ "$PLATFORM" = "Linux" ] ; then { - sysctl -w kernel.core_pattern=core + sysctl -w kernel.core_uses_pid=0 + # Arch Linux requires core_pattern to be empty :( + test -e /etc/arch-release && sysctl -w kernel.core_pattern= + test -e /etc/arch-release || sysctl -w kernel.core_pattern=core sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.sched_child_runs_first=1 sysctl -w kernel.sched_autogroup_enabled=1 @@ -86,14 +89,15 @@ if [ "$PLATFORM" = "NetBSD" ] ; then DONE=1 fi if [ "$PLATFORM" = "Darwin" ] ; then + sysctl kern.sysv.shmmax=8388608 + sysctl kern.sysv.shmseg=48 + sysctl kern.sysv.shmall=98304 if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then echo We unload the default crash reporter here SL=/System/Library; PL=com.apple.ReportCrash launchctl unload -w ${SL}/LaunchAgents/${PL}.plist sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist echo Settings applied. - else - echo Nothing to do. fi DONE=1 fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 31351a58..ceb02bb9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -44,6 +44,8 @@ sending a mail to . - fix MIPS delay slot caching, thanks @JackGrence - fixed aarch64 exit address - execution no longer stops at address 0x0 + - updated afl-system-config to support Arch Linux weirdness and increase + MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup -- cgit 1.4.1 From 8b7a7b29c60f11cdf6226b3e418e87a5c3f5caac Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 10 May 2021 13:57:47 +0200 Subject: Push to stable (#895) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev --- README.md | 4 +- afl-plot | 10 +- afl-system-config | 10 +- custom_mutators/README.md | 8 + custom_mutators/examples/Makefile | 7 + custom_mutators/examples/README.md | 35 ++ custom_mutators/examples/XmlMutatorMin.py | 348 ++++++++++++++++ custom_mutators/examples/common.py | 40 ++ custom_mutators/examples/custom_mutator_helpers.h | 342 +++++++++++++++ custom_mutators/examples/example.c | 376 +++++++++++++++++ custom_mutators/examples/example.py | 187 +++++++++ custom_mutators/examples/post_library_gif.so.c | 165 ++++++++ custom_mutators/examples/post_library_png.so.c | 163 ++++++++ custom_mutators/examples/simple-chunk-replace.py | 66 +++ custom_mutators/examples/simple_example.c | 74 ++++ custom_mutators/examples/wrapper_afl_min.py | 123 ++++++ custom_mutators/grammar_mutator/GRAMMAR_VERSION | 2 +- custom_mutators/grammar_mutator/grammar_mutator | 2 +- docs/Changelog.md | 14 +- docs/custom_mutators.md | 4 +- docs/env_variables.md | 4 + docs/life_pro_tips.md | 2 +- frida_mode/GNUmakefile | 181 ++++++++ frida_mode/Makefile | 349 +--------------- frida_mode/README.md | 153 +++---- frida_mode/include/entry.h | 15 + frida_mode/include/frida_cmplog.h | 14 + frida_mode/include/instrument.h | 22 +- frida_mode/include/interceptor.h | 7 + frida_mode/include/lib.h | 13 + frida_mode/include/persistent.h | 31 ++ frida_mode/include/prefetch.h | 12 +- frida_mode/include/ranges.h | 7 +- frida_mode/include/stalker.h | 11 + frida_mode/include/util.h | 14 + frida_mode/src/cmplog/cmplog.c | 87 ++++ frida_mode/src/cmplog/cmplog_arm.c | 19 + frida_mode/src/cmplog/cmplog_arm64.c | 19 + frida_mode/src/cmplog/cmplog_x64.c | 346 +++++++++++++++ frida_mode/src/cmplog/cmplog_x86.c | 19 + frida_mode/src/entry.c | 50 +++ frida_mode/src/instrument.c | 271 ------------ frida_mode/src/instrument/instrument.c | 155 +++++++ frida_mode/src/instrument/instrument_arm32.c | 23 + frida_mode/src/instrument/instrument_arm64.c | 97 +++++ frida_mode/src/instrument/instrument_x64.c | 93 +++++ frida_mode/src/instrument/instrument_x86.c | 23 + frida_mode/src/interceptor.c | 21 +- frida_mode/src/lib/lib.c | 176 ++++++++ frida_mode/src/lib/lib_apple.c | 82 ++++ frida_mode/src/main.c | 72 ++-- frida_mode/src/persistent/persistent.c | 65 +++ frida_mode/src/persistent/persistent_arm32.c | 72 ++++ frida_mode/src/persistent/persistent_arm64.c | 115 +++++ frida_mode/src/persistent/persistent_x64.c | 342 +++++++++++++++ frida_mode/src/persistent/persistent_x86.c | 55 +++ frida_mode/src/prefetch.c | 23 +- frida_mode/src/ranges.c | 462 ++++++++++++++------- frida_mode/src/stalker.c | 30 ++ frida_mode/src/util.c | 67 +++ frida_mode/test/cmplog/GNUmakefile | 66 +++ frida_mode/test/cmplog/Makefile | 12 + frida_mode/test/cmplog/get_section_addrs.py | 49 +++ frida_mode/test/entry_point/GNUmakefile | 61 +++ frida_mode/test/entry_point/Makefile | 12 + frida_mode/test/entry_point/testinstr.c | 119 ++++++ frida_mode/test/exe/GNUmakefile | 50 +++ frida_mode/test/exe/Makefile | 12 + frida_mode/test/exe/testinstr.c | 112 +++++ frida_mode/test/png/GNUmakefile | 109 +++++ frida_mode/test/png/Makefile | 12 + frida_mode/test/png/persistent/GNUmakefile | 79 ++++ frida_mode/test/png/persistent/Makefile | 18 + frida_mode/test/png/persistent/get_symbol_addr.py | 36 ++ frida_mode/test/png/persistent/hook/GNUmakefile | 98 +++++ frida_mode/test/png/persistent/hook/Makefile | 18 + frida_mode/test/testinstr.c | 112 ----- frida_mode/test/testinstr.py | 49 --- frida_mode/test/testinstr/GNUmakefile | 50 +++ frida_mode/test/testinstr/Makefile | 12 + frida_mode/test/testinstr/testinstr.c | 112 +++++ frida_mode/update_frida_version.sh | 13 + include/afl-fuzz.h | 6 +- include/envs.h | 4 + instrumentation/README.llvm.md | 2 +- instrumentation/SanitizerCoverageLTO.so.cc | 15 +- instrumentation/SanitizerCoveragePCGUARD.so.cc | 102 ++--- instrumentation/afl-compiler-rt.o.c | 15 +- instrumentation/afl-gcc-pass.so.cc | 4 +- instrumentation/afl-llvm-common.cc | 4 +- instrumentation/afl-llvm-lto-instrumentation.so.cc | 8 +- instrumentation/split-switches-pass.so.cc | 2 +- qemu_mode/README.md | 4 +- qemu_mode/build_qemu_support.sh | 2 +- src/afl-cc.c | 4 +- src/afl-forkserver.c | 5 +- src/afl-fuzz-bitmap.c | 2 +- src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-init.c | 10 +- src/afl-fuzz-mutators.c | 54 ++- src/afl-fuzz-one.c | 4 +- src/afl-fuzz-run.c | 10 +- src/afl-fuzz-state.c | 8 + src/afl-fuzz-stats.c | 16 +- src/afl-fuzz.c | 38 +- src/afl-ld-lto.c | 11 +- test/test-all.sh | 2 + test/test-custom-mutators.sh | 6 +- test/test-frida-mode.sh | 108 +++++ test/test-performance.sh | 1 + test/test-pre.sh | 1 + unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/samples/speedtest/c/Makefile | 10 +- unicorn_mode/samples/speedtest/python/Makefile | 11 +- unicorn_mode/samples/speedtest/rust/Makefile | 12 +- unicorn_mode/unicornafl | 2 +- utils/README.md | 3 +- utils/afl_proxy/afl-proxy.c | 29 +- utils/aflpp_driver/GNUmakefile | 6 +- utils/aflpp_driver/aflpp_qemu_driver_hook.c | 10 +- utils/custom_mutators/Makefile | 7 - utils/custom_mutators/README.md | 35 -- utils/custom_mutators/XmlMutatorMin.py | 348 ---------------- utils/custom_mutators/common.py | 40 -- utils/custom_mutators/custom_mutator_helpers.h | 342 --------------- utils/custom_mutators/example.c | 376 ----------------- utils/custom_mutators/example.py | 187 --------- utils/custom_mutators/post_library_gif.so.c | 165 -------- utils/custom_mutators/post_library_png.so.c | 163 -------- utils/custom_mutators/simple-chunk-replace.py | 66 --- utils/custom_mutators/simple_example.c | 74 ---- utils/custom_mutators/wrapper_afl_min.py | 123 ------ utils/libdislocator/libdislocator.so.c | 21 +- utils/qbdi_mode/template.cpp | 2 +- utils/qemu_persistent_hook/read_into_rdi.c | 10 +- 135 files changed, 6136 insertions(+), 3168 deletions(-) create mode 100644 custom_mutators/examples/Makefile create mode 100644 custom_mutators/examples/README.md create mode 100644 custom_mutators/examples/XmlMutatorMin.py create mode 100644 custom_mutators/examples/common.py create mode 100644 custom_mutators/examples/custom_mutator_helpers.h create mode 100644 custom_mutators/examples/example.c create mode 100644 custom_mutators/examples/example.py create mode 100644 custom_mutators/examples/post_library_gif.so.c create mode 100644 custom_mutators/examples/post_library_png.so.c create mode 100644 custom_mutators/examples/simple-chunk-replace.py create mode 100644 custom_mutators/examples/simple_example.c create mode 100644 custom_mutators/examples/wrapper_afl_min.py create mode 100644 frida_mode/GNUmakefile create mode 100644 frida_mode/include/entry.h create mode 100644 frida_mode/include/frida_cmplog.h create mode 100644 frida_mode/include/lib.h create mode 100644 frida_mode/include/persistent.h create mode 100644 frida_mode/include/stalker.h create mode 100644 frida_mode/include/util.h create mode 100644 frida_mode/src/cmplog/cmplog.c create mode 100644 frida_mode/src/cmplog/cmplog_arm.c create mode 100644 frida_mode/src/cmplog/cmplog_arm64.c create mode 100644 frida_mode/src/cmplog/cmplog_x64.c create mode 100644 frida_mode/src/cmplog/cmplog_x86.c create mode 100644 frida_mode/src/entry.c delete mode 100644 frida_mode/src/instrument.c create mode 100644 frida_mode/src/instrument/instrument.c create mode 100644 frida_mode/src/instrument/instrument_arm32.c create mode 100644 frida_mode/src/instrument/instrument_arm64.c create mode 100644 frida_mode/src/instrument/instrument_x64.c create mode 100644 frida_mode/src/instrument/instrument_x86.c create mode 100644 frida_mode/src/lib/lib.c create mode 100644 frida_mode/src/lib/lib_apple.c create mode 100644 frida_mode/src/persistent/persistent.c create mode 100644 frida_mode/src/persistent/persistent_arm32.c create mode 100644 frida_mode/src/persistent/persistent_arm64.c create mode 100644 frida_mode/src/persistent/persistent_x64.c create mode 100644 frida_mode/src/persistent/persistent_x86.c create mode 100644 frida_mode/src/stalker.c create mode 100644 frida_mode/src/util.c create mode 100644 frida_mode/test/cmplog/GNUmakefile create mode 100644 frida_mode/test/cmplog/Makefile create mode 100755 frida_mode/test/cmplog/get_section_addrs.py create mode 100644 frida_mode/test/entry_point/GNUmakefile create mode 100644 frida_mode/test/entry_point/Makefile create mode 100644 frida_mode/test/entry_point/testinstr.c create mode 100644 frida_mode/test/exe/GNUmakefile create mode 100644 frida_mode/test/exe/Makefile create mode 100644 frida_mode/test/exe/testinstr.c create mode 100644 frida_mode/test/png/GNUmakefile create mode 100644 frida_mode/test/png/Makefile create mode 100644 frida_mode/test/png/persistent/GNUmakefile create mode 100644 frida_mode/test/png/persistent/Makefile create mode 100755 frida_mode/test/png/persistent/get_symbol_addr.py create mode 100644 frida_mode/test/png/persistent/hook/GNUmakefile create mode 100644 frida_mode/test/png/persistent/hook/Makefile delete mode 100644 frida_mode/test/testinstr.c delete mode 100755 frida_mode/test/testinstr.py create mode 100644 frida_mode/test/testinstr/GNUmakefile create mode 100644 frida_mode/test/testinstr/Makefile create mode 100644 frida_mode/test/testinstr/testinstr.c create mode 100755 frida_mode/update_frida_version.sh create mode 100755 test/test-frida-mode.sh delete mode 100644 utils/custom_mutators/Makefile delete mode 100644 utils/custom_mutators/README.md delete mode 100644 utils/custom_mutators/XmlMutatorMin.py delete mode 100644 utils/custom_mutators/common.py delete mode 100644 utils/custom_mutators/custom_mutator_helpers.h delete mode 100644 utils/custom_mutators/example.c delete mode 100644 utils/custom_mutators/example.py delete mode 100644 utils/custom_mutators/post_library_gif.so.c delete mode 100644 utils/custom_mutators/post_library_png.so.c delete mode 100644 utils/custom_mutators/simple-chunk-replace.py delete mode 100644 utils/custom_mutators/simple_example.c delete mode 100644 utils/custom_mutators/wrapper_afl_min.py (limited to 'docs') diff --git a/README.md b/README.md index 4a0f3574..c16216bf 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,9 @@ behaviours and defaults: | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| | NeverZero | x86[_64]| x(1) | x | | x | x | - | Persistent Mode | | x | x | | x86[_64]/arm[64] | x | + | Persistent Mode | | x | x | x | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | | x86[_64]/arm[64] | | + | CmpLog | | x | | x | x86[_64]/arm[64] | | | Selective Instrumentation| | x | x | x | x | | | Non-Colliding Coverage | | x(4) | | | (x)(5) | | | Ngram prev_loc Coverage | | x(6) | | | | | diff --git a/afl-plot b/afl-plot index ba100d3e..26c8d1b7 100755 --- a/afl-plot +++ b/afl-plot @@ -111,9 +111,9 @@ set terminal png truecolor enhanced size 1000,300 butt set output '$outputdir/high_freq.png' -set xdata time -set timefmt '%s' -set format x "%b %d\n%H:%M" +#set xdata time +#set timefmt '%s' +#set format x "%b %d\n%H:%M" set tics font 'small' unset mxtics unset mytics @@ -129,7 +129,6 @@ set autoscale xfixmax set xlabel "all times in UTC" font "small" -set ytics auto plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\ '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\ '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\ @@ -139,7 +138,6 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin set terminal png truecolor enhanced size 1000,200 butt set output '$outputdir/low_freq.png' -set ytics 1 plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\ '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\ '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\ @@ -148,14 +146,12 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb set terminal png truecolor enhanced size 1000,200 butt set output '$outputdir/exec_speed.png' -set ytics auto plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\ '$inputdir/plot_data' using 1:11 with lines title ' execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier; set terminal png truecolor enhanced size 1000,300 butt set output '$outputdir/edges.png' -set ytics auto plot '$inputdir/plot_data' using 1:13 with lines title ' edges' linecolor rgb '#0090ff' linewidth 3 _EOF_ diff --git a/afl-system-config b/afl-system-config index 5ad9d937..e08871ac 100755 --- a/afl-system-config +++ b/afl-system-config @@ -22,7 +22,10 @@ if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then fi if [ "$PLATFORM" = "Linux" ] ; then { - sysctl -w kernel.core_pattern=core + sysctl -w kernel.core_uses_pid=0 + # Arch Linux requires core_pattern to be empty :( + test -e /etc/arch-release && sysctl -w kernel.core_pattern= + test -e /etc/arch-release || sysctl -w kernel.core_pattern=core sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.sched_child_runs_first=1 sysctl -w kernel.sched_autogroup_enabled=1 @@ -86,14 +89,15 @@ if [ "$PLATFORM" = "NetBSD" ] ; then DONE=1 fi if [ "$PLATFORM" = "Darwin" ] ; then + sysctl kern.sysv.shmmax=8388608 + sysctl kern.sysv.shmseg=48 + sysctl kern.sysv.shmall=98304 if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then echo We unload the default crash reporter here SL=/System/Library; PL=com.apple.ReportCrash launchctl unload -w ${SL}/LaunchAgents/${PL}.plist sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist echo Settings applied. - else - echo Nothing to do. fi DONE=1 fi diff --git a/custom_mutators/README.md b/custom_mutators/README.md index b0444c85..5e1d0fe6 100644 --- a/custom_mutators/README.md +++ b/custom_mutators/README.md @@ -3,6 +3,14 @@ Custom mutators enhance and alter the mutation strategies of afl++. For further information and documentation on how to write your own, read [the docs](../docs/custom_mutators.md). +## Examples + +The `./examples` folder contains examples for custom mutators in python and C. + +## Rust + +In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`. + ## The afl++ Grammar Mutator If you use git to clone afl++, then the following will incorporate our diff --git a/custom_mutators/examples/Makefile b/custom_mutators/examples/Makefile new file mode 100644 index 00000000..9849f3f4 --- /dev/null +++ b/custom_mutators/examples/Makefile @@ -0,0 +1,7 @@ +all: libexamplemutator.so + +libexamplemutator.so: + $(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so + +clean: + rm -rf libexamplemutator.so diff --git a/custom_mutators/examples/README.md b/custom_mutators/examples/README.md new file mode 100644 index 00000000..655f7a5e --- /dev/null +++ b/custom_mutators/examples/README.md @@ -0,0 +1,35 @@ +# Examples for the custom mutator + +These are example and helper files for the custom mutator feature. +See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information + +Note that if you compile with python3.7 you must use python3 scripts, and if +you use python2.7 to compile python2 scripts! + +simple_example.c - most simplest example. generates a random sized buffer + filled with 'A' + +example.c - this is a simple example written in C and should be compiled to a + shared library. Use make to compile it and produce libexamplemutator.so + +example.py - this is the template you can use, the functions are there but they + are empty + +post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF + +post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG + +simple-chunk-replace.py - this is a simple example where chunks are replaced + +common.py - this can be used for common functions and helpers. + the examples do not use this though. But you can :) + +wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py + +XmlMutatorMin.py - module for XML mutation + +custom_mutator_helpers.h is an header that defines some helper routines +like surgical_havoc_mutate() that allow to perform a randomly chosen +mutation from a subset of the havoc mutations. +If you do so, you have to specify -I /path/to/AFLplusplus/include when +compiling. diff --git a/custom_mutators/examples/XmlMutatorMin.py b/custom_mutators/examples/XmlMutatorMin.py new file mode 100644 index 00000000..3e6cd0ff --- /dev/null +++ b/custom_mutators/examples/XmlMutatorMin.py @@ -0,0 +1,348 @@ +#!/usr/bin/python + +""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """ + +from __future__ import print_function +from copy import deepcopy +from lxml import etree as ET +import random, re, io + + +########################### +# The XmlMutatorMin class # +########################### + + +class XmlMutatorMin: + + """ + Optionals parameters: + seed Seed used by the PRNG (default: "RANDOM") + verbose Verbosity (default: False) + """ + + def __init__(self, seed="RANDOM", verbose=False): + + """ Initialize seed, database and mutators """ + + # Verbosity + self.verbose = verbose + + # Initialize PRNG + self.seed = str(seed) + if self.seed == "RANDOM": + random.seed() + else: + if self.verbose: + print("Static seed '%s'" % self.seed) + random.seed(self.seed) + + # Initialize input and output documents + self.input_tree = None + self.tree = None + + # High-level mutators (no database needed) + hl_mutators_delete = [ + "del_node_and_children", + "del_node_but_children", + "del_attribute", + "del_content", + ] # Delete items + hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values + + # Exposed mutators + self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete + + def __parse_xml(self, xml): + + """ Parse an XML string. Basic wrapper around lxml.parse() """ + + try: + # Function parse() takes care of comments / DTD / processing instructions / ... + tree = ET.parse(io.BytesIO(xml)) + except ET.ParseError: + raise RuntimeError("XML isn't well-formed!") + except LookupError as e: + raise RuntimeError(e) + + # Return a document wrapper + return tree + + def __exec_among(self, module, functions, min_times, max_times): + + """ Randomly execute $functions between $min and $max times """ + + for i in xrange(random.randint(min_times, max_times)): + # Function names are mangled because they are "private" + getattr(module, "_XmlMutatorMin__" + random.choice(functions))() + + def __serialize_xml(self, tree): + + """ Serialize a XML document. Basic wrapper around lxml.tostring() """ + + return ET.tostring( + tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding + ) + + def __ver(self, version): + + """ Helper for displaying lxml version numbers """ + + return ".".join(map(str, version)) + + def reset(self): + + """ Reset the mutator """ + + self.tree = deepcopy(self.input_tree) + + def init_from_string(self, input_string): + + """ Initialize the mutator from a XML string """ + + # Get a pointer to the top-element + self.input_tree = self.__parse_xml(input_string) + + # Get a working copy + self.tree = deepcopy(self.input_tree) + + def save_to_string(self): + + """ Return the current XML document as UTF-8 string """ + + # Return a text version of the tree + return self.__serialize_xml(self.tree) + + def __pick_element(self, exclude_root_node=False): + + """ Pick a random element from the current document """ + + # Get a list of all elements, but nodes like PI and comments + elems = list(self.tree.getroot().iter(tag=ET.Element)) + + # Is the root node excluded? + if exclude_root_node: + start = 1 + else: + start = 0 + + # Pick a random element + try: + elem_id = random.randint(start, len(elems) - 1) + elem = elems[elem_id] + except ValueError: + # Should only occurs if "exclude_root_node = True" + return (None, None) + + return (elem_id, elem) + + def __fuzz_attribute(self): + + """ Fuzz (part of) an attribute value """ + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Get all the attributes + attribs = rand_elem.keys() + + # Is there attributes? + if len(attribs) < 1: + if self.verbose: + print("No attribute: can't replace!") + return + + # Pick a random attribute + rand_attrib_id = random.randint(0, len(attribs) - 1) + rand_attrib = attribs[rand_attrib_id] + + # We have the attribute to modify + # Get its value + attrib_value = rand_elem.get(rand_attrib) + # print("- Value: " + attrib_value) + + # Should we work on the whole value? + func_call = "(?P[a-zA-Z:\-]+)\((?P.*?)\)" + p = re.compile(func_call) + l = p.findall(attrib_value) + if random.choice((True, False)) and l: + # Randomly pick one the function calls + (func, args) = random.choice(l) + # Split by "," and randomly pick one of the arguments + value = random.choice(args.split(",")) + # Remove superfluous characters + unclean_value = value + value = value.strip(" ").strip("'") + # print("Selected argument: [%s]" % value) + else: + value = attrib_value + + # For each type, define some possible replacement values + choices_number = ( + "0", + "11111", + "-128", + "2", + "-1", + "1/3", + "42/0", + "1094861636 idiv 1.0", + "-1123329771506872 idiv 3.8", + "17=$numericRTF", + str(3 + random.randrange(0, 100)), + ) + + choices_letter = ( + "P" * (25 * random.randrange(1, 100)), + "%s%s%s%s%s%s", + "foobar", + ) + + choices_alnum = ( + "Abc123", + "020F0302020204030204", + "020F0302020204030204" * (random.randrange(5, 20)), + ) + + # Fuzz the value + if random.choice((True, False)) and value == "": + + # Empty + new_value = value + + elif random.choice((True, False)) and value.isdigit(): + + # Numbers + new_value = random.choice(choices_number) + + elif random.choice((True, False)) and value.isalpha(): + + # Letters + new_value = random.choice(choices_letter) + + elif random.choice((True, False)) and value.isalnum(): + + # Alphanumeric + new_value = random.choice(choices_alnum) + + else: + + # Default type + new_value = random.choice(choices_alnum + choices_letter + choices_number) + + # If we worked on a substring, apply changes to the whole string + if value != attrib_value: + # No ' around empty values + if new_value != "" and value != "": + new_value = "'" + new_value + "'" + # Apply changes + new_value = attrib_value.replace(unclean_value, new_value) + + # Log something + if self.verbose: + print( + "Fuzzing attribute #%i '%s' of tag #%i '%s'" + % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) + ) + + # Modify the attribute + rand_elem.set(rand_attrib, new_value.decode("utf-8")) + + def __del_node_and_children(self): + + """High-level minimizing mutator + Delete a random node and its children (i.e. delete a random tree)""" + + self.__del_node(True) + + def __del_node_but_children(self): + + """High-level minimizing mutator + Delete a random node but its children (i.e. link them to the parent of the deleted node)""" + + self.__del_node(False) + + def __del_node(self, delete_children): + + """ Called by the __del_node_* mutators """ + + # Select a node to modify (but the root one) + (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True) + + # If the document includes only a top-level element + # Then we can't pick a element (given that "exclude_root_node = True") + + # Is the document deep enough? + if rand_elem is None: + if self.verbose: + print("Can't delete a node: document not deep enough!") + return + + # Log something + if self.verbose: + but_or_and = "and" if delete_children else "but" + print( + "Deleting tag #%i '%s' %s its children" + % (rand_elem_id, rand_elem.tag, but_or_and) + ) + + if delete_children is False: + # Link children of the random (soon to be deleted) node to its parent + for child in rand_elem: + rand_elem.getparent().append(child) + + # Remove the node + rand_elem.getparent().remove(rand_elem) + + def __del_content(self): + + """High-level minimizing mutator + Delete the attributes and children of a random node""" + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Log something + if self.verbose: + print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) + + # Reset the node + rand_elem.clear() + + def __del_attribute(self): + + """High-level minimizing mutator + Delete a random attribute from a random node""" + + # Select a node to modify + (rand_elem_id, rand_elem) = self.__pick_element() + + # Get all the attributes + attribs = rand_elem.keys() + + # Is there attributes? + if len(attribs) < 1: + if self.verbose: + print("No attribute: can't delete!") + return + + # Pick a random attribute + rand_attrib_id = random.randint(0, len(attribs) - 1) + rand_attrib = attribs[rand_attrib_id] + + # Log something + if self.verbose: + print( + "Deleting attribute #%i '%s' of tag #%i '%s'" + % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) + ) + + # Delete the attribute + rand_elem.attrib.pop(rand_attrib) + + def mutate(self, min=1, max=5): + + """ Execute some high-level mutators between $min and $max times, then some medium-level ones """ + + # High-level mutation + self.__exec_among(self, self.hl_mutators_all, min, max) diff --git a/custom_mutators/examples/common.py b/custom_mutators/examples/common.py new file mode 100644 index 00000000..44a5056a --- /dev/null +++ b/custom_mutators/examples/common.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Module containing functions shared between multiple AFL modules + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +from __future__ import print_function +import random +import os +import re + + +def randel(l): + if not l: + return None + return l[random.randint(0, len(l) - 1)] + + +def randel_pop(l): + if not l: + return None + return l.pop(random.randint(0, len(l) - 1)) + + +def write_exc_example(data, exc): + exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc)) + + if not os.path.exists(exc_name): + with open(exc_name, "w") as f: + f.write(data) diff --git a/custom_mutators/examples/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h new file mode 100644 index 00000000..62e6efba --- /dev/null +++ b/custom_mutators/examples/custom_mutator_helpers.h @@ -0,0 +1,342 @@ +#ifndef CUSTOM_MUTATOR_HELPERS +#define CUSTOM_MUTATOR_HELPERS + +#include "config.h" +#include "types.h" +#include + +#define INITIAL_GROWTH_SIZE (64) + +#define RAND_BELOW(limit) (rand() % (limit)) + +/* Use in a struct: creates a name_buf and a name_size variable. */ +#define BUF_VAR(type, name) \ + type * name##_buf; \ + size_t name##_size; +/* this fills in `&structptr->something_buf, &structptr->something_size`. */ +#define BUF_PARAMS(struct, name) \ + (void **)&struct->name##_buf, &struct->name##_size + +typedef struct { + +} afl_t; + +static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { + + static s8 interesting_8[] = {INTERESTING_8}; + static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; + static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; + + switch (RAND_BELOW(12)) { + + case 0: { + + /* Flip a single bit somewhere. Spooky! */ + + s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); + + out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); + + break; + + } + + case 1: { + + /* Set byte to interesting value. */ + + u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; + out_buf[(RAND_BELOW(end - begin) + begin)] = val; + + break; + + } + + case 2: { + + /* Set word to interesting value, randomly choosing endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u16 *)(out_buf + byte_idx) = + interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; + break; + case 1: + *(u16 *)(out_buf + byte_idx) = + SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); + break; + + } + + break; + + } + + case 3: { + + /* Set dword to interesting value, randomly choosing endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u32 *)(out_buf + byte_idx) = + interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u32 *)(out_buf + byte_idx) = + SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 4: { + + /* Set qword to interesting value, randomly choosing endian. */ + + if (end - begin < 8) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 7) break; + + switch (RAND_BELOW(2)) { + + case 0: + *(u64 *)(out_buf + byte_idx) = + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; + break; + case 1: + *(u64 *)(out_buf + byte_idx) = SWAP64( + (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); + break; + + } + + break; + + } + + case 5: { + + /* Randomly subtract from byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 6: { + + /* Randomly add to byte. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); + + break; + + } + + case 7: { + + /* Randomly subtract from word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 8: { + + /* Randomly add to word, random endian. */ + + if (end - begin < 2) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 1) break; + + if (RAND_BELOW(2)) { + + *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u16 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u16 *)(out_buf + byte_idx) = + SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 9: { + + /* Randomly subtract from dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); + + } + + break; + + } + + case 10: { + + /* Randomly add to dword, random endian. */ + + if (end - begin < 4) break; + + s32 byte_idx = (RAND_BELOW(end - begin) + begin); + + if (byte_idx >= end - 3) break; + + if (RAND_BELOW(2)) { + + *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); + + } else { + + u32 num = 1 + RAND_BELOW(ARITH_MAX); + + *(u32 *)(out_buf + byte_idx) = + SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); + + } + + break; + + } + + case 11: { + + /* Just set a random byte to a random value. Because, + why not. We use XOR with 1-255 to eliminate the + possibility of a no-op. */ + + out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); + + break; + + } + + } + +} + +/* This function calculates the next power of 2 greater or equal its argument. + @return The rounded up power of 2 (if no overflow) or 0 on overflow. +*/ +static inline size_t next_pow2(size_t in) { + + if (in == 0 || in > (size_t)-1) + return 0; /* avoid undefined behaviour under-/overflow */ + size_t out = in - 1; + out |= out >> 1; + out |= out >> 2; + out |= out >> 4; + out |= out >> 8; + out |= out >> 16; + return out + 1; + +} + +/* This function makes sure *size is > size_needed after call. + It will realloc *buf otherwise. + *size will grow exponentially as per: + https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ + Will return NULL and free *buf if size_needed is <1 or realloc failed. + @return For convenience, this function returns *buf. + */ +static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { + + /* No need to realloc */ + if (likely(size_needed && *size >= size_needed)) return *buf; + + /* No initial size was set */ + if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; + + /* grow exponentially */ + size_t next_size = next_pow2(size_needed); + + /* handle overflow */ + if (!next_size) { next_size = size_needed; } + + /* alloc */ + *buf = realloc(*buf, next_size); + *size = *buf ? next_size : 0; + + return *buf; + +} + +/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ +static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, + size_t *size2) { + + void * scratch_buf = *buf1; + size_t scratch_size = *size1; + *buf1 = *buf2; + *size1 = *size2; + *buf2 = scratch_buf; + *size2 = scratch_size; + +} + +#undef INITIAL_GROWTH_SIZE + +#endif + diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c new file mode 100644 index 00000000..23add128 --- /dev/null +++ b/custom_mutators/examples/example.c @@ -0,0 +1,376 @@ +/* + New Custom Mutator for AFL++ + Written by Khaled Yakdan + Andrea Fioraldi + Shengtuo Hu + Dominik Maier +*/ + +// You need to use -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#define DATA_SIZE (100) + +static const char *commands[] = { + + "GET", + "PUT", + "DEL", + +}; + +typedef struct my_mutator { + + afl_t *afl; + + // any additional data here! + size_t trim_size_current; + int trimmming_steps; + int cur_step; + + // Reused buffers: + BUF_VAR(u8, fuzz); + BUF_VAR(u8, data); + BUF_VAR(u8, havoc); + BUF_VAR(u8, trim); + BUF_VAR(u8, post_process); + +} my_mutator_t; + +/** + * Initialize this custom mutator + * + * @param[in] afl a pointer to the internal state object. Can be ignored for + * now. + * @param[in] seed A seed for this mutator - the same seed should always mutate + * in the same way. + * @return Pointer to the data object this custom mutator instance should use. + * There may be multiple instances of this mutator in one afl-fuzz run! + * Return NULL on error. + */ +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); // needed also by surgical_havoc_mutate() + + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +/** + * Perform custom mutations on a given input + * + * (Optional for now. Required in the future) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to input data to be mutated + * @param[in] buf_size Size of input data + * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on + * error. + * @param[in] add_buf Buffer containing the additional test case + * @param[in] add_buf_size Size of the additional test case + * @param[in] max_size Maximum size of the mutated output. The mutation must not + * produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + // Make sure that the packet size does not exceed the maximum size expected by + // the fuzzer + size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; + + // maybe_grow is optimized to be quick for reused buffers. + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + // Randomly select a command string to add as a header to the packet + memcpy(mutated_out, commands[rand() % 3], 3); + + // Mutate the payload of the packet + int i; + for (i = 0; i < 8; ++i) { + + // Randomly perform one of the (no len modification) havoc mutations + surgical_havoc_mutate(mutated_out, 3, mutated_size); + + } + + *out_buf = mutated_out; + return mutated_size; + +} + +/** + * A post-processing function to use right before AFL writes the test case to + * disk in order to execute the target. + * + * (Optional) If this functionality is not needed, simply don't define this + * function. + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Buffer containing the test case to be executed + * @param[in] buf_size Size of the test case + * @param[out] out_buf Pointer to the buffer containing the test case after + * processing. External library should allocate memory for out_buf. + * The buf pointer may be reused (up to the given buf_size); + * @return Size of the output buffer after processing or the needed amount. + * A return of 0 indicates an error. + */ +size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, + size_t buf_size, uint8_t **out_buf) { + + uint8_t *post_process_buf = + maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); + if (!post_process_buf) { + + perror("custom mutator realloc failed."); + *out_buf = NULL; + return 0; + + } + + memcpy(post_process_buf + 5, buf, buf_size); + post_process_buf[0] = 'A'; + post_process_buf[1] = 'F'; + post_process_buf[2] = 'L'; + post_process_buf[3] = '+'; + post_process_buf[4] = '+'; + + *out_buf = post_process_buf; + + return buf_size + 5; + +} + +/** + * This method is called at the start of each trimming operation and receives + * the initial buffer. It should return the amount of iteration steps possible + * on this input (e.g. if your input has n elements and you want to remove + * them one by one, return n, if you do a binary search, return log(n), + * and so on...). + * + * If your trimming algorithm doesn't allow you to determine the amount of + * (remaining) steps easily (esp. while running), then you can alternatively + * return 1 here and always return 0 in post_trim until you are finished and + * no steps remain. In that case, returning 1 in post_trim will end the + * trimming routine. The whole current index/max iterations stuff is only used + * to show progress. + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param buf Buffer containing the test case + * @param buf_size Size of the test case + * @return The amount of possible iteration steps to trim the input. + * negative on error. + */ +int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, + size_t buf_size) { + + // We simply trim once + data->trimmming_steps = 1; + + data->cur_step = 0; + + if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { + + perror("init_trim grow"); + return -1; + + } + + memcpy(data->trim_buf, buf, buf_size); + + data->trim_size_current = buf_size; + + return data->trimmming_steps; + +} + +/** + * This method is called for each trimming operation. It doesn't have any + * arguments because we already have the initial buffer from init_trim and we + * can memorize the current state in *data. This can also save + * reparsing steps for each iteration. It should return the trimmed input + * buffer, where the returned data must not exceed the initial input data in + * length. Returning anything that is larger than the original data (passed + * to init_trim) will result in a fatal abort of AFLFuzz. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[out] out_buf Pointer to the buffer containing the trimmed test case. + * External library should allocate memory for out_buf. + * AFL++ will not release the memory after saving the test case. + * Keep a ref in *data. + * *out_buf = NULL is treated as error. + * @return Pointer to the size of the trimmed test case + */ +size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { + + *out_buf = data->trim_buf; + + // Remove the last byte of the trimming input + return data->trim_size_current - 1; + +} + +/** + * This method is called after each trim operation to inform you if your + * trimming step was successful or not (in terms of coverage). If you receive + * a failure here, you should reset your input to the last known good state. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param success Indicates if the last trim operation was successful. + * @return The next trim iteration index (from 0 to the maximum amount of + * steps returned in init_trim). negative ret on failure. + */ +int32_t afl_custom_post_trim(my_mutator_t *data, int success) { + + if (success) { + + ++data->cur_step; + return data->cur_step; + + } + + return data->trimmming_steps; + +} + +/** + * Perform a single custom mutation on a given input. + * This mutation is stacked with the other muatations in havoc. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param[in] buf Pointer to the input data to be mutated and the mutated + * output + * @param[in] buf_size Size of input data + * @param[out] out_buf The output buffer. buf can be reused, if the content + * fits. *out_buf = NULL is treated as error. + * @param[in] max_size Maximum size of the mutated output. The mutation must + * not produce data larger than max_size. + * @return Size of the mutated output. + */ +size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { + + if (buf_size == 0) { + + *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); + if (!*out_buf) { + + perror("custom havoc: maybe_grow"); + return 0; + + } + + **out_buf = rand() % 256; + buf_size = 1; + + } else { + + // We reuse buf here. It's legal and faster. + *out_buf = buf; + + } + + size_t victim = rand() % buf_size; + (*out_buf)[victim] += rand() % 10; + + return buf_size; + +} + +/** + * Return the probability (in percentage) that afl_custom_havoc_mutation + * is called in havoc. By default it is 6 %. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @return The probability (0-100). + */ +uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { + + return 5; // 5 % + +} + +/** + * Determine whether the fuzzer should fuzz the queue entry or not. + * + * (Optional) + * + * @param[in] data pointer returned in afl_custom_init for this fuzz case + * @param filename File name of the test case in the queue entry + * @return Return True(1) if the fuzzer will fuzz the queue entry, and + * False(0) otherwise. + */ +uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { + + return 1; + +} + +/** + * Allow for additional analysis (e.g. calling a different tool that does a + * different kind of coverage and saves this for the custom mutator). + * + * (Optional) + * + * @param data pointer returned in afl_custom_init for this fuzz case + * @param filename_new_queue File name of the new queue entry + * @param filename_orig_queue File name of the original queue entry + */ +void afl_custom_queue_new_entry(my_mutator_t * data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { + + /* Additional analysis on the original or new test case */ + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->post_process_buf); + free(data->havoc_buf); + free(data->data_buf); + free(data->fuzz_buf); + free(data->trim_buf); + free(data); + +} + diff --git a/custom_mutators/examples/example.py b/custom_mutators/examples/example.py new file mode 100644 index 00000000..3a6d22e4 --- /dev/null +++ b/custom_mutators/examples/example.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Example Python Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +import random + + +COMMANDS = [ + b"GET", + b"PUT", + b"DEL", + b"AAAAAAAAAAAAAAAAA", +] + + +def init(seed): + """ + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + """ + random.seed(seed) + + +def deinit(): + pass + + +def fuzz(buf, add_buf, max_size): + """ + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + """ + ret = bytearray(100) + + ret[:3] = random.choice(COMMANDS) + + return ret + + +# Uncomment and implement the following methods if you want to use a custom +# trimming algorithm. See also the documentation for a better API description. + +# def init_trim(buf): +# ''' +# Called per trimming iteration. +# +# @type buf: bytearray +# @param buf: The buffer that should be trimmed. +# +# @rtype: int +# @return: The maximum number of trimming steps. +# ''' +# global ... +# +# # Initialize global variables +# +# # Figure out how many trimming steps are possible. +# # If this is not possible for your trimming, you can +# # return 1 instead and always return 0 in post_trim +# # until you are done (then you return 1). +# +# return steps +# +# def trim(): +# ''' +# Called per trimming iteration. +# +# @rtype: bytearray +# @return: A new bytearray containing the trimmed data. +# ''' +# global ... +# +# # Implement the actual trimming here +# +# return bytearray(...) +# +# def post_trim(success): +# ''' +# Called after each trimming operation. +# +# @type success: bool +# @param success: Indicates if the last trim operation was successful. +# +# @rtype: int +# @return: The next trim index (0 to max number of steps) where max +# number of steps indicates the trimming is done. +# ''' +# global ... +# +# if not success: +# # Restore last known successful input, determine next index +# else: +# # Just determine the next index, based on what was successfully +# # removed in the last step +# +# return next_index +# +# def post_process(buf): +# ''' +# Called just before the execution to write the test case in the format +# expected by the target +# +# @type buf: bytearray +# @param buf: The buffer containing the test case to be executed +# +# @rtype: bytearray +# @return: The buffer containing the test case after +# ''' +# return buf +# +# def havoc_mutation(buf, max_size): +# ''' +# Perform a single custom mutation on a given input. +# +# @type buf: bytearray +# @param buf: The buffer that should be mutated. +# +# @type max_size: int +# @param max_size: Maximum size of the mutated output. The mutation must not +# produce data larger than max_size. +# +# @rtype: bytearray +# @return: A new bytearray containing the mutated data +# ''' +# return mutated_buf +# +# def havoc_mutation_probability(): +# ''' +# Called for each `havoc_mutation`. Return the probability (in percentage) +# that `havoc_mutation` is called in havoc. Be default it is 6%. +# +# @rtype: int +# @return: The probability (0-100) +# ''' +# return prob +# +# def queue_get(filename): +# ''' +# Called at the beginning of each fuzz iteration to determine whether the +# test case should be fuzzed +# +# @type filename: str +# @param filename: File name of the test case in the current queue entry +# +# @rtype: bool +# @return: Return True if the custom mutator decides to fuzz the test case, +# and False otherwise +# ''' +# return True +# +# def queue_new_entry(filename_new_queue, filename_orig_queue): +# ''' +# Called after adding a new test case to the queue +# +# @type filename_new_queue: str +# @param filename_new_queue: File name of the new queue entry +# +# @type filename_orig_queue: str +# @param filename_orig_queue: File name of the original queue entry +# ''' +# pass diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c new file mode 100644 index 00000000..ac10f409 --- /dev/null +++ b/custom_mutators/examples/post_library_gif.so.c @@ -0,0 +1,165 @@ +/* + american fuzzy lop++ - postprocessor library example + -------------------------------------------------- + + Originally written by Michal Zalewski + Edited by Dominik Maier, 2020 + + Copyright 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Postprocessor libraries can be passed to afl-fuzz to perform final cleanup + of any mutated test cases - for example, to fix up checksums in PNG files. + + Please heed the following warnings: + + 1) In almost all cases, it is more productive to comment out checksum logic + in the targeted binary (as shown in ../libpng_no_checksum/). One possible + exception is the process of fuzzing binary-only software in QEMU mode. + + 2) The use of postprocessors for anything other than checksums is + questionable and may cause more harm than good. AFL is normally pretty good + about dealing with length fields, magic values, etc. + + 3) Postprocessors that do anything non-trivial must be extremely robust to + gracefully handle malformed data and other error conditions - otherwise, + they will crash and take afl-fuzz down with them. Be wary of reading past + *len and of integer overflows when calculating file offsets. + + In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, + honestly know what you're doing =) + + With that out of the way: the postprocessor library is passed to afl-fuzz + via AFL_POST_LIBRARY. The library must be compiled with: + + gcc -shared -Wall -O3 post_library.so.c -o post_library.so + + AFL will call the afl_custom_post_process() function for every mutated output + buffer. From there, you have three choices: + + 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` + and return the original `len`. + + 2) If you want to skip this test case altogether and have AFL generate a + new one, return 0 or set `*out_buf = NULL`. + Use this sparingly - it's faster than running the target program + with patently useless inputs, but still wastes CPU time. + + 3) If you want to modify the test case, allocate an appropriately-sized + buffer, move the data into that buffer, make the necessary changes, and + then return the new pointer as out_buf. Return an appropriate len + afterwards. + + Note that the buffer will *not* be freed for you. To avoid memory leaks, + you need to free it or reuse it on subsequent calls (as shown below). + + *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** + + Aight. The example below shows a simple postprocessor that tries to make + sure that all input files start with "GIF89a". + + PS. If you don't like C, you can try out the unix-based wrapper from + Ben Nagy instead: https://github.com/bnagy/aflfix + + */ + +#include +#include +#include + +/* Header that must be present at the beginning of every test case: */ + +#define HEADER "GIF89a" + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +/* The actual postprocessor routine called by afl-fuzz: */ + +size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, + unsigned int len, unsigned char **out_buf) { + + /* Skip execution altogether for buffers shorter than 6 bytes (just to + show how it's done). We can trust len to be sane. */ + + if (len < strlen(HEADER)) return 0; + + /* Do nothing for buffers that already start with the expected header. */ + + if (!memcmp(in_buf, HEADER, strlen(HEADER))) { + + *out_buf = in_buf; + return len; + + } + + /* Allocate memory for new buffer, reusing previous allocation if + possible. */ + + *out_buf = realloc(data->buf, len); + + /* If we're out of memory, the most graceful thing to do is to return the + original buffer and give up on modifying it. Let AFL handle OOM on its + own later on. */ + + if (!*out_buf) { + + *out_buf = in_buf; + return len; + + } + + /* Copy the original data to the new location. */ + + memcpy(*out_buf, in_buf, len); + + /* Insert the new header. */ + + memcpy(*out_buf, HEADER, strlen(HEADER)); + + /* Return the new len. It hasn't changed, so it's just len. */ + + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c new file mode 100644 index 00000000..941f7e55 --- /dev/null +++ b/custom_mutators/examples/post_library_png.so.c @@ -0,0 +1,163 @@ +/* + american fuzzy lop++ - postprocessor for PNG + ------------------------------------------ + + Originally written by Michal Zalewski + + Copyright 2015 Google Inc. All rights reserved. + Adapted to the new API, 2020 by Dominik Maier + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + See post_library.so.c for a general discussion of how to implement + postprocessors. This specific postprocessor attempts to fix up PNG + checksums, providing a slightly more complicated example than found + in post_library.so.c. + + Compile with: + + gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz + + */ + +#include +#include +#include +#include +#include + +#include + +/* A macro to round an integer up to 4 kB. */ + +#define UP4K(_i) ((((_i) >> 12) + 1) << 12) + +typedef struct post_state { + + unsigned char *buf; + size_t size; + +} post_state_t; + +void *afl_custom_init(void *afl) { + + post_state_t *state = malloc(sizeof(post_state_t)); + if (!state) { + + perror("malloc"); + return NULL; + + } + + state->buf = calloc(sizeof(unsigned char), 4096); + if (!state->buf) { + + free(state); + perror("calloc"); + return NULL; + + } + + return state; + +} + +size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, + unsigned int len, + const unsigned char **out_buf) { + + unsigned char *new_buf = (unsigned char *)in_buf; + unsigned int pos = 8; + + /* Don't do anything if there's not enough room for the PNG header + (8 bytes). */ + + if (len < 8) { + + *out_buf = in_buf; + return len; + + } + + /* Minimum size of a zero-length PNG chunk is 12 bytes; if we + don't have that, we can bail out. */ + + while (pos + 12 <= len) { + + unsigned int chunk_len, real_cksum, file_cksum; + + /* Chunk length is the first big-endian dword in the chunk. */ + + chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); + + /* Bail out if chunk size is too big or goes past EOF. */ + + if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; + + /* Chunk checksum is calculated for chunk ID (dword) and the actual + payload. */ + + real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); + + /* The in-file checksum is the last dword past the chunk data. */ + + file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); + + /* If the checksums do not match, we need to fix the file. */ + + if (real_cksum != file_cksum) { + + /* First modification? Make a copy of the input buffer. Round size + up to 4 kB to minimize the number of reallocs needed. */ + + if (new_buf == in_buf) { + + if (len <= data->size) { + + new_buf = data->buf; + + } else { + + new_buf = realloc(data->buf, UP4K(len)); + if (!new_buf) { + + *out_buf = in_buf; + return len; + + } + + data->buf = new_buf; + data->size = UP4K(len); + memcpy(new_buf, in_buf, len); + + } + + } + + *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; + + } + + /* Skip the entire chunk and move to the next one. */ + + pos += 12 + chunk_len; + + } + + *out_buf = new_buf; + return len; + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/custom_mutators/examples/simple-chunk-replace.py b/custom_mutators/examples/simple-chunk-replace.py new file mode 100644 index 00000000..c57218dd --- /dev/null +++ b/custom_mutators/examples/simple-chunk-replace.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Simple Chunk Cross-Over Replacement Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +import random + + +def init(seed): + """ + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + """ + # Seed our RNG + random.seed(seed) + + +def fuzz(buf, add_buf, max_size): + """ + Called per fuzzing iteration. + + @type buf: bytearray + @param buf: The buffer that should be mutated. + + @type add_buf: bytearray + @param add_buf: A second buffer that can be used as mutation source. + + @type max_size: int + @param max_size: Maximum size of the mutated output. The mutation must not + produce data larger than max_size. + + @rtype: bytearray + @return: A new bytearray containing the mutated data + """ + # Make a copy of our input buffer for returning + ret = bytearray(buf) + + # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) + fragment_len = random.randint(1, min(len(add_buf), 32)) + + # Determine a random source index where to take the data chunk from + rand_src_idx = random.randint(0, len(add_buf) - fragment_len) + + # Determine a random destination index where to put the data chunk + rand_dst_idx = random.randint(0, len(buf)) + + # Make the chunk replacement + ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[ + rand_src_idx : rand_src_idx + fragment_len + ] + + # Return data + return ret diff --git a/custom_mutators/examples/simple_example.c b/custom_mutators/examples/simple_example.c new file mode 100644 index 00000000..d888ec1f --- /dev/null +++ b/custom_mutators/examples/simple_example.c @@ -0,0 +1,74 @@ +// This simple example just creates random buffer <= 100 filled with 'A' +// needs -I /path/to/AFLplusplus/include +#include "custom_mutator_helpers.h" + +#include +#include +#include +#include + +#ifndef _FIXED_CHAR + #define _FIXED_CHAR 0x41 +#endif + +typedef struct my_mutator { + + afl_t *afl; + + // Reused buffers: + BUF_VAR(u8, fuzz); + +} my_mutator_t; + +my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { + + srand(seed); + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, + size_t add_buf_size, // add_buf can be NULL + size_t max_size) { + + int size = (rand() % 100) + 1; + if (size > max_size) size = max_size; + u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); + if (!mutated_out) { + + *out_buf = NULL; + perror("custom mutator allocation (maybe_grow)"); + return 0; /* afl-fuzz will very likely error out after this. */ + + } + + memset(mutated_out, _FIXED_CHAR, size); + + *out_buf = mutated_out; + return size; + +} + +/** + * Deinitialize everything + * + * @param data The data ptr from afl_custom_init + */ +void afl_custom_deinit(my_mutator_t *data) { + + free(data->fuzz_buf); + free(data); + +} + diff --git a/custom_mutators/examples/wrapper_afl_min.py b/custom_mutators/examples/wrapper_afl_min.py new file mode 100644 index 00000000..5cd60031 --- /dev/null +++ b/custom_mutators/examples/wrapper_afl_min.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +from XmlMutatorMin import XmlMutatorMin + +# Default settings (production mode) + +__mutator__ = None +__seed__ = "RANDOM" +__log__ = False +__log_file__ = "wrapper.log" + + +# AFL functions +def log(text): + """ + Logger + """ + + global __seed__ + global __log__ + global __log_file__ + + if __log__: + with open(__log_file__, "a") as logf: + logf.write("[%s] %s\n" % (__seed__, text)) + + +def init(seed): + """ + Called once when AFL starts up. Seed is used to identify the AFL instance in log files + """ + + global __mutator__ + global __seed__ + + # Get the seed + __seed__ = seed + + # Create a global mutation class + try: + __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) + log("init(): Mutator created") + except RuntimeError as e: + log("init(): Can't create mutator: %s" % e.message) + + +def fuzz(buf, add_buf, max_size): + """ + Called for each fuzzing iteration. + """ + + global __mutator__ + + # Do we have a working mutator object? + if __mutator__ is None: + log("fuzz(): Can't fuzz, no mutator available") + return buf + + # Try to use the AFL buffer + via_buffer = True + + # Interpret the AFL buffer (an array of bytes) as a string + if via_buffer: + try: + buf_str = str(buf) + log("fuzz(): AFL buffer converted to a string") + except Exception: + via_buffer = False + log("fuzz(): Can't convert AFL buffer to a string") + + # Load XML from the AFL string + if via_buffer: + try: + __mutator__.init_from_string(buf_str) + log( + "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" + % len(buf_str) + ) + except Exception: + via_buffer = False + log("fuzz(): Can't initialize mutator with AFL buffer") + + # If init from AFL buffer wasn't succesful + if not via_buffer: + log("fuzz(): Returning unmodified AFL buffer") + return buf + + # Sucessful initialization -> mutate + try: + __mutator__.mutate(max=5) + log("fuzz(): Input mutated") + except Exception: + log("fuzz(): Can't mutate input => returning buf") + return buf + + # Convert mutated data to a array of bytes + try: + data = bytearray(__mutator__.save_to_string()) + log("fuzz(): Mutated data converted as bytes") + except Exception: + log("fuzz(): Can't convert mutated data to bytes => returning buf") + return buf + + # Everything went fine, returning mutated content + log("fuzz(): Returning %d bytes" % len(data)) + return data + + +# Main (for debug) +if __name__ == "__main__": + + __log__ = True + __log_file__ = "/dev/stdout" + __seed__ = "RANDOM" + + init(__seed__) + + in_1 = bytearray( + "ffffzzzzzzzzzzzz" + ) + in_2 = bytearray("") + out = fuzz(in_1, in_2) + print(out) diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION index c7c1948d..3df8150e 100644 --- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION +++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION @@ -1 +1 @@ -a2d4e4a +b79d51a diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator index a2d4e4ab..b79d51a8 160000 --- a/custom_mutators/grammar_mutator/grammar_mutator +++ b/custom_mutators/grammar_mutator/grammar_mutator @@ -1 +1 @@ -Subproject commit a2d4e4ab966f0581219fbb282f5ac8c89e85ead9 +Subproject commit b79d51a8daccbd7a693f9b6765c81ead14f28e26 diff --git a/docs/Changelog.md b/docs/Changelog.md index 520b13b1..ceb02bb9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,7 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, + it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! - create a fuzzing dictionary with the help of CodeQL thanks to @microsvuln! see utils/autodict_ql @@ -19,6 +20,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - fixed a bug when trimming for stdin targets - default cmplog level (-l) is now 2, better efficiency. - cmplog level 3 (-l 3) now performs redqueen on everything. use with care. @@ -31,10 +33,20 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - afl-cc: - We do not support llvm versions prior 6.0 anymore + - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode + - utils/aflpp_driver: + - aflpp_qemu_driver_hook fixed to work with qemu_mode + - aflpp_driver now compiled with -fPIC + - unicornafl: + - fix MIPS delay slot caching, thanks @JackGrence + - fixed aarch64 exit address + - execution no longer stops at address 0x0 + - updated afl-system-config to support Arch Linux weirdness and increase + MacOS shared memory + - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 62e01f83..9d5381e8 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -285,8 +285,8 @@ afl-fuzz /path/to/program ## 4) Example -Please see [example.c](../utils/custom_mutators/example.c) and -[example.py](../utils/custom_mutators/example.py) +Please see [example.c](../custom_mutators/examples/example.c) and +[example.py](../custom_mutators/examples/example.py) ## 5) Other Resources diff --git a/docs/env_variables.md b/docs/env_variables.md index 0100ffac..8879db72 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -284,6 +284,10 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were + found within a specified period of time. May be convenient for some + types of automated jobs. + - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md index 50ad75d4..13ffcea0 100644 --- a/docs/life_pro_tips.md +++ b/docs/life_pro_tips.md @@ -83,5 +83,5 @@ 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 utils/custom_mutators/ for more. +See `afl_custom_post_process` in custom_mutators/examples/example.c for more. diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile new file mode 100644 index 00000000..a15f5c32 --- /dev/null +++ b/frida_mode/GNUmakefile @@ -0,0 +1,181 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)..)/ +INC_DIR:=$(PWD)include/ +SRC_DIR:=$(PWD)src/ +INCLUDES:=$(wildcard $(INC_DIR)*.h) +BUILD_DIR:=$(PWD)build/ +OBJ_DIR:=$(BUILD_DIR)obj/ + +SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c) +OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))) +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -D_FORTIFY_SOURCE=2 \ + -g \ + -O3 \ + -funroll-loops \ + +RT_CFLAGS:=-Wno-unused-parameter \ + -Wno-sign-compare \ + -Wno-unused-function \ + -Wno-unused-result \ + +LDFLAGS+=-shared \ + -lpthread \ + -lresolv \ + -ldl \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ +FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so +FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif + +ifeq "$(shell uname)" "Darwin" + OS:=macos + RT_CFLAGS:=$(RT_CFLAGS) -Wno-deprecated-declarations +else +ifdef DEBUG + RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor +endif +endif + +ifeq "$(shell uname)" "Linux" + OS:=linux +endif + +ifndef OS + $(error "Operating system unsupported") +endif + +GUM_DEVKIT_VERSION=14.2.18 +GUM_DEVKIT_FILENAME=frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz +GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" + +GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) +GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a +GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h + +FRIDA_DIR:=$(PWD)build/frida-source/ +FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile +FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a +FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/ +FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h +FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar +FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME) + +AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c +AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o + +.PHONY: all clean format $(FRIDA_GUM) + +############################## ALL ############################################# + +all: $(FRIDA_TRACE) + make -C $(ROOT) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(OBJ_DIR): | $(BUILD_DIR) + mkdir -p $@ + +############################# FRIDA ############################################ + +$(FRIDA_MAKEFILE): | $(BUILD_DIR) + git clone --recursive https://github.com/frida/frida.git $(FRIDA_DIR) + +$(FRIDA_GUM): $(FRIDA_MAKEFILE) + cd $(FRIDA_DIR) && make gum-linux-$(ARCH) + +$(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM) + $(FRIDA_DIR)releng/devkit.py frida-gum linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/ + +$(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER) + cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) . + +$(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL): $(FRIDA_GUM_DEVKIT_TARBALL) + xz -k -f -0 $(FRIDA_GUM_DEVKIT_TARBALL) + +############################# DEVKIT ########################################### + +$(FRIDA_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +ifdef FRIDA_SOURCE +$(GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL)| $(FRIDA_BUILD_DIR) + cp -v $< $@ +else +$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) + wget -O $@ $(GUM_DEVKIT_URL) +endif + +$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) + tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) + +############################## AFL ############################################# +$(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC) + $(CC) \ + $(CFLAGS) \ + $(RT_CFLAGS) \ + -I $(ROOT) \ + -I $(ROOT)include \ + -o $@ \ + -c $< + +############################# SOURCE ########################################### + +define BUILD_SOURCE +$(2): $(1) $(INCLUDES) GNUmakefile | $(OBJ_DIR) + $(CC) \ + $(CFLAGS) \ + -I $(ROOT)include \ + -I $(FRIDA_BUILD_DIR) \ + -I $(INC_DIR) \ + -c $1 \ + -o $2 +endef + +$(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))))) + +######################## AFL-FRIDA-TRACE ####################################### + +$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR) + $(CC) \ + -o $@ \ + $(OBJS) \ + $(GUM_DEVIT_LIBRARY) \ + $(AFL_COMPILER_RT_OBJ) \ + $(LDFLAGS) \ + + cp -v $(FRIDA_TRACE) $(ROOT) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/Makefile b/frida_mode/Makefile index 822f1c6a..b6d64bff 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -1,348 +1,9 @@ -PWD:=$(shell pwd)/ -INC_DIR:=$(PWD)include/ -SRC_DIR:=$(PWD)src/ -INCLUDES:=$(wildcard $(INC_DIR)*.h) -SOURCES:=$(wildcard $(SRC_DIR)*.c) -BUILD_DIR:=$(PWD)build/ -CFLAGS+=-fPIC -D_GNU_SOURCE +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake -FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ -FRIDA_TRACE:=$(FRIDA_BUILD_DIR)afl-frida-trace.so - -ARCH=$(shell uname -m) -ifeq "$(ARCH)" "aarch64" - ARCH:=arm64 - TESTINSTR_BASE:=0x0000aaaaaaaaa000 -endif - -ifeq "$(ARCH)" "x86_64" - TESTINSTR_BASE:=0x0000555555554000 -endif - -ifeq "$(shell uname)" "Darwin" - OS:=macos - AFL_FRIDA_INST_RANGES=0x0000000000001000-0xFFFFFFFFFFFFFFFF - CFLAGS:=$(CFLAGS) -Wno-deprecated-declarations - TEST_LDFLAGS:=-undefined dynamic_lookup -endif -ifeq "$(shell uname)" "Linux" - OS:=linux - AFL_FRIDA_INST_RANGES=$(shell $(PWD)test/testinstr.py -f $(BUILD_DIR)testinstr -s .testinstr -b $(TESTINSTR_BASE)) - CFLAGS:=$(CFLAGS) -Wno-prio-ctor-dtor - TEST_LDFLAGS:= -endif - -ifndef OS - $(error "Operating system unsupported") -endif - -VERSION=14.2.13 -GUM_DEVKIT_FILENAME=frida-gum-devkit-$(VERSION)-$(OS)-$(ARCH).tar.xz -GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(VERSION)/$(GUM_DEVKIT_FILENAME)" -GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) -GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a -GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h - -TEST_BUILD_DIR:=$(BUILD_DIR)test/ - -LIBPNG_FILE:=$(TEST_BUILD_DIR)libpng-1.2.56.tar.gz -LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz -LIBPNG_DIR:=$(TEST_BUILD_DIR)libpng-1.2.56/ -LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile -LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a - -HARNESS_FILE:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.c -HARNESS_OBJ:=$(TEST_BUILD_DIR)StandaloneFuzzTargetMain.o -HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" - -PNGTEST_FILE:=$(TEST_BUILD_DIR)target.cc -PNGTEST_OBJ:=$(TEST_BUILD_DIR)target.o -PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" - -TEST_BIN:=$(TEST_BUILD_DIR)pngtest - -TESTINSTBIN:=$(BUILD_DIR)testinstr -TESTINSTSRC:=$(PWD)test/testinstr.c - -TEST_DATA_DIR:=$(PWD)build/test/libpng-1.2.56/contrib/pngsuite/ - -TESTINSTR_DATA_DIR:=$(BUILD_DIR)testinstr_in/ -TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)test.dat -FRIDA_OUT:=$(PWD)frida_out -QEMU_OUT:=$(PWD)qemu_out - -.PHONY: all frida test clean format test_frida test_qemu compare testinstr test_testinstr standalone - -all: $(FRIDA_TRACE) - -frida: $(FRIDA_TRACE) - -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - -############################# FRIDA ############################################ -$(FRIDA_BUILD_DIR): | $(BUILD_DIR) - mkdir -p $@ - -$(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) - wget -O $@ $(GUM_DEVKIT_URL) - -$(GUM_DEVIT_LIBRARY): | $(GUM_DEVKIT_TARBALL) - tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) - -$(GUM_DEVIT_HEADER): | $(GUM_DEVKIT_TARBALL) - tar Jxvf $(GUM_DEVKIT_TARBALL) -C $(FRIDA_BUILD_DIR) - -$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(SOURCES) Makefile | $(FRIDA_BUILD_DIR) - $(CC) -shared \ - $(CFLAGS) \ - -o $@ $(SOURCES) \ - $(GUM_DEVIT_LIBRARY) \ - -I $(FRIDA_BUILD_DIR) \ - -I .. \ - -I ../include \ - -I $(INC_DIR) \ - ../instrumentation/afl-compiler-rt.o.c \ - -lpthread -ldl -lresolv - - cp -v $(FRIDA_TRACE) ../ - -############################# TEST ############################################# - -test: $(TEST_BIN) - -$(TEST_BUILD_DIR): $(BUILD_DIR) - mkdir -p $@ - -$(HARNESS_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(HARNESS_URL) - -$(HARNESS_OBJ): $(HARNESS_FILE) - $(CC) -o $@ -c $< - -$(PNGTEST_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(PNGTEST_URL) - -$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) - $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< - -$(LIBPNG_FILE): | $(TEST_BUILD_DIR) - wget -O $@ $(LIBPNG_URL) - -$(LIBPNG_DIR): $(LIBPNG_FILE) - tar zxvf $(LIBPNG_FILE) -C $(TEST_BUILD_DIR) - -$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) - cd $(LIBPNG_DIR) && ./configure - -$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) - make -C $(LIBPNG_DIR) - -$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) - $(CXX) \ - -o $@ \ - $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ - -lz \ - $(TEST_LDFLAGS) - -############################# TESTINSR ######################################### -$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) - mkdir -p $@ - -$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) - echo -n "000" > $@ - -$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) -o $@ $< - -testinstr: $(TESTINSTBIN) - -############################# CLEAN ############################################ clean: - rm -rf $(BUILD_DIR) + @gmake clean -############################# FORMAT ########################################### format: - cd .. && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i - cd .. && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i - cd .. && ./.custom-format.py -i $(TESTINSTSRC) - -############################# RUN ############################################# - -# Add the environment variable AFL_DEBUG_CHILD=1 to show printf's from the target - -png_frida: $(FRIDA_TRACE) $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-fuzz \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -png_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-fuzz \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -compare: $(FRIDA_TRACE) $(TEST_BIN) - cd .. && \ - ./afl-fuzz \ - -V30 \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - cd .. && \ - ./afl-fuzz \ - -V30 \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - cat frida_out/default/fuzzer_stats - cat qemu_out/default/fuzzer_stats - -testinstr_qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - make -C .. - cd .. && \ - AFL_QEMU_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - ./afl-fuzz \ - -Q \ - -i $(TESTINSTR_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TESTINSTBIN) @@ - -testinstr_frida: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - make -C .. - cd .. && \ - AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - AFL_FRIDA_INST_NO_OPTIMIZE=1 \ - AFL_FRIDA_INST_NO_PREFETCH=1 \ - AFL_FRIDA_INST_STRICT=1 \ - ./afl-fuzz \ - -O \ - -i $(TESTINSTR_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TESTINSTBIN) @@ - -standalone: $(FRIDA_TRACE) $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - cd .. && \ - AFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ - AFL_DEBUG_CHILD=1 \ - AFL_FRIDA_DEBUG_MAPS=1 \ - AFL_FRIDA_INST_NO_OPTIMIZE=1 \ - AFL_FRIDA_INST_NO_PREFETCH=1 \ - AFL_FRIDA_INST_TRACE=1 \ - AFL_FRIDA_INST_STRICT=1 \ - LD_PRELOAD=$(FRIDA_TRACE) \ - DYLD_INSERT_LIBRARIES=$(FRIDA_TRACE) \ - $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - -tmin_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-tmin \ - -Q \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -o $(QEMU_OUT)/qemu-min-basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -tmin_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-tmin \ - -O \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -o $(FRIDA_OUT)/qemu-min-basn0g01.png \ - -- \ - $(TEST_BIN) - -showmap_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-showmap \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -showmap_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-showmap \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -analyze_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-analyze \ - -Q \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -analyze_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-analyze \ - -O \ - -i $(TEST_DATA_DIR)basn0g01.png \ - -- \ - $(TEST_BIN) @@ - -cmin_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_bash_qemu: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin.bash \ - -Q \ - -i $(TEST_DATA_DIR) \ - -o $(QEMU_OUT) \ - -- \ - $(TEST_BIN) @@ - -cmin_bash_frida: $(TEST_BIN) - make -C .. - cd .. && \ - ./afl-cmin.bash \ - -O \ - -i $(TEST_DATA_DIR) \ - -o $(FRIDA_OUT) \ - -- \ - $(TEST_BIN) @@ + @gmake format diff --git a/frida_mode/README.md b/frida_mode/README.md index 8abee0dd..9f574a4c 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -1,34 +1,38 @@ # FRIDA MODE -The purpose of FRIDA mode is to provide an alternative binary only fuzzer for AFL -just like that provided by QEMU mode. The intention is to provide a very similar -user experience, right down to the options provided through environment variables. + +The purpose of FRIDA mode is to provide an alternative binary only fuzzer for +AFL just like that provided by QEMU mode. The intention is to provide a very +similar user experience, right down to the options provided through environment +variables. Whilst AFLplusplus already has some support for running on FRIDA [here](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) this requires the code to be fuzzed to be provided as a shared library, it cannot be used to fuzz executables. Additionally, it requires the user to write -a small harness around their target code of interest, FRIDA mode instead takes a -different approach to avoid these limitations. - -# Current Progress -As FRIDA mode is new, it is missing a lot of features. Most importantly, -persistent mode. The design is such that it should be possible to add these -features in a similar manner to QEMU mode and perhaps leverage some of its -design and implementation. - - | Feature/Instrumentation | frida-mode | - | -------------------------|:----------:| - | NeverZero | | - | Persistent Mode | | - | LAF-Intel / CompCov | | - | CmpLog | | - | Selective Instrumentation| x | - | Non-Colliding Coverage | | - | Ngram prev_loc Coverage | | - | Context Coverage | | - | Auto Dictionary | | - | Snapshot LKM Support | | - -# Compatibility +a small harness around their target code of interest. +FRIDA mode instead takes a different approach to avoid these limitations. +In Frida mode binary programs are instrumented, similarly to QEMU mode. + +## Current Progress + +As FRIDA mode is new, it is missing a lot of features. The design is such that it +should be possible to add these features in a similar manner to QEMU mode and +perhaps leverage some of its design and implementation. + + | Feature/Instrumentation | frida-mode | Notes | + | -------------------------|:----------:|:---------------------------------------:| + | NeverZero | x | | + | Persistent Mode | x | (x64 only)(Only on function boundaries) | + | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | + | CMPLOG | x | (x64 only) | + | Selective Instrumentation| x | | + | Non-Colliding Coverage | - | | + | Ngram prev_loc Coverage | - | | + | Context Coverage | - | | + | Auto Dictionary | - | | + | Snapshot LKM Support | - | | + | In-Memory Test Cases | x | (x64 only) | + +## Compatibility Currently FRIDA mode supports Linux and macOS targets on both x86/x64 architecture and aarch64. Later releases may add support for aarch32 and Windows targets as well as embedded linux environments. @@ -38,54 +42,53 @@ runtime libraries, so porting should be possible. However, the current build system does not support cross compilation. ## Getting Started + To build everything run `make`. -To run the benchmark sample with qemu run `make png_qemu`. -To run the benchmark sample with frida run `make png_frida`. +Various tests can be found in subfolders within the `test/` directory. To use +these, first run `make` to build any dependencies. Then run `make qemu` or +`make frida` to run on either QEMU of FRIDA mode respectively. ## Usage -FRIDA mode requires some small modifications to `afl-fuzz` and similar tools -in AFLplusplus. The intention is that it behaves identically to QEMU, but uses + +FRIDA mode added some small modifications to `afl-fuzz` and similar tools +in AFLplusplus. The intention was that it behaves identically to QEMU, but it uses the 'O' switch rather than 'Q'. Whilst the options 'f', 'F', 's' or 'S' may have made more sense for a mode powered by FRIDA Stalker, they were all taken, so instead we use 'O' in hommage to the [author](https://github.com/oleavr) of FRIDA. Similarly, the intention is to mimic the use of environment variables used by -QEMU where possible (although replacing `s/QEMU/FRIDA/g`). Accodingly, the -following options are currently supported. +QEMU where possible (by replacing `s/QEMU/FRIDA/g`). Accordingly, the +following options are currently supported: * `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` * `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` * `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` +* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR` +* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` +* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` -# Performance +To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`. + +## Performance Additionally, the intention is to be able to make a direct performance -comparison between the two approaches. Accordingly, FRIDA mode includes a test -target based on the [libpng](https://libpng.sourceforge.io/) benchmark used by -[fuzzbench](https://google.github.io/fuzzbench/) and integrated with the +comparison between the two approaches. Accordingly, FRIDA mode includes various +test targets based on the [libpng](https://libpng.sourceforge.io/) benchmark +used by [fuzzbench](https://google.github.io/fuzzbench/) and integrated with the [StandaloneFuzzTargetMain](https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c) -from the llvm project. This is built and linked without any special -modifications to suit FRIDA or QEMU. We use the test data provided with libpng -as our corpus. - -Whilst not much performance tuning has been completed to date, performance is -around 30-50% of that of QEMU mode, however, this gap may reduce with the -introduction of persistent mode. Performance can be tested by running -`make compare`, albeit a longer time measurement may be required for more -accurate results. - -Whilst [afl_frida](https://github.com/AFLplusplus/AFLplusplus/tree/stable/utils/afl_frida) -claims a 5-10x performance increase over QEMU, it has not been possible to -reproduce these claims. However, the number of executions per second can vary -dramatically as a result of the randomization of the fuzzer input. Some inputs -may traverse relatively few paths before being rejected as invalid whilst others -may be valid inputs or be subject to much more processing before rejection. -Accordingly, it is recommended that testing be carried out over prolongued -periods to gather timings which are more than indicative. - -# Design +from the llvm project. These tests include basic fork-server support, persistent +mode and persistent mode with in-memory test-cases. These are built and linked +without any special modifications to suit FRIDA or QEMU. The test data provided +with libpng is used as the corpus. + +The intention is to add support for FRIDA mode to the FuzzBench project and +perform a like-for-like comparison with QEMU mode to get an accurate +appreciation of its performance. + +## Design + FRIDA mode is supported by using `LD_PRELOAD` (`DYLD_INSERT_LIBRARIES` on macOS) to inject a shared library (`afl-frida-trace.so`) into the target. This shared library is built using the [frida-gum](https://github.com/frida/frida-gum) @@ -102,34 +105,34 @@ this coverage information to AFL++ and also provide a fork server. It also makes use of the FRIDA [prefetch](https://github.com/frida/frida-gum/blob/56dd9ba3ee9a5511b4b0c629394bf122775f1ab7/gum/gumstalker.h#L115) support to feedback instrumented blocks from the child to the parent using a shared memory region to avoid the need to regenerate instrumented blocks on each -fork. +fork. Whilst FRIDA allows for a normal C function to be used to augment instrumented -code, to minimize the costs of storing and restoring all of the registers, FRIDA -mode instead makes use of optimized assembly instead on AARCH64 and x86/64 -targets. +code, FRIDA mode instead makes use of optimized assembly instead on AARCH64 and +x86/64 targets. By injecting these small snippets of assembly, we avoid having +to push and pop the full register context. Note that since this instrumentation +is used on every basic block to generate coverage, it has a large impact on +performance. + +CMPLOG support also adds code to the assembly, however, at present this code +makes use of a basic C function and is yet to be optimized. Since not all +instances run CMPLOG mode and instrumentation of the binary is less frequent +(only on CMP, SUB and CALL instructions) performance is not quite so critical. + +## Advanced configuration options -# Advanced configuration options * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. -* `AFL_FRIDA_INST_STRICT` - Under certain conditions, Stalker may encroach into -excluded regions and generate both instrumented blocks and coverage data (e.g. -indirect calls on x86). The excluded block is generally honoured as soon as -another function is called within the excluded region and so such encroachment -is usually of little consequence. This detail may however, hinder you when -checking that the correct number of paths are found for testing purposes or -similar. There is a performance penatly for this option during block compilation -where we check the block isn't in a list of excluded ranges. * `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. -# TODO -As can be seen from the progress section above, there are a number of features -which are missing in its currently form. Chief amongst which is persistent mode. -The intention is to achieve feature parity with QEMU mode in due course. -Contributions are welcome, but please get in touch to ensure that efforts are -deconflicted. +## TODO + +The next features to be added are x86 support, integration with FuzzBench and +support for ASAN. The intention is to achieve feature parity with QEMU mode in +due course. Contributions are welcome, but please get in touch to ensure that +efforts are deconflicted. diff --git a/frida_mode/include/entry.h b/frida_mode/include/entry.h new file mode 100644 index 00000000..967831af --- /dev/null +++ b/frida_mode/include/entry.h @@ -0,0 +1,15 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include "frida-gum.h" + +extern guint64 entry_start; + +void entry_init(void); + +void entry_run(void); + +void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output); + +#endif + diff --git a/frida_mode/include/frida_cmplog.h b/frida_mode/include/frida_cmplog.h new file mode 100644 index 00000000..28864c0e --- /dev/null +++ b/frida_mode/include/frida_cmplog.h @@ -0,0 +1,14 @@ +#ifndef _CMPLOG_H +#define _CMPLOG_H + +extern struct cmp_map *__afl_cmp_map; + +void cmplog_init(void); + +/* Functions to be implemented by the different architectures */ +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +gboolean cmplog_is_readable(void *addr, size_t size); + +#endif + diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index ff71bed4..03fd33e5 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -1,7 +1,23 @@ +#ifndef _INSTRUMENT_H +#define _INSTRUMENT_H + #include "frida-gum.h" -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); +#include "config.h" + +extern __thread uint64_t previous_pc; +extern uint8_t * __afl_area_ptr; +extern uint32_t __afl_map_size; + +void instrument_init(void); + +GumStalkerTransformer *instrument_get_transformer(void); + +/* Functions to be implemented by the different architectures */ +gboolean instrument_is_coverage_optimize_supported(void); + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output); -void instrument_init(); +#endif diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h index 5ed3cf49..0ff754a4 100644 --- a/frida_mode/include/interceptor.h +++ b/frida_mode/include/interceptor.h @@ -1,4 +1,11 @@ +#ifndef _INTERCEPTOR_H +#define _INTERCEPTOR_H + #include "frida-gum.h" void intercept(void *address, gpointer replacement, gpointer user_data); +void unintercept(void *address); +void unintercept_self(void); + +#endif diff --git a/frida_mode/include/lib.h b/frida_mode/include/lib.h new file mode 100644 index 00000000..237aecb0 --- /dev/null +++ b/frida_mode/include/lib.h @@ -0,0 +1,13 @@ +#ifndef _LIB_H +#define _LIB_H + +#include "frida-gum.h" + +void lib_init(void); + +guint64 lib_get_text_base(void); + +guint64 lib_get_text_limit(void); + +#endif + diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h new file mode 100644 index 00000000..e58c5301 --- /dev/null +++ b/frida_mode/include/persistent.h @@ -0,0 +1,31 @@ + +#ifndef _PERSISTENT_H +#define _PERSISTENT_H + +#include "frida-gum.h" +#include "config.h" + +typedef struct arch_api_regs api_regs; + +typedef void (*afl_persistent_hook_fn)(api_regs *regs, uint64_t guest_base, + uint8_t *input_buf, + uint32_t input_buf_len); + +extern int __afl_persistent_loop(unsigned int max_cnt); + +extern unsigned int * __afl_fuzz_len; +extern unsigned char *__afl_fuzz_ptr; + +extern guint64 persistent_start; +extern guint64 persistent_count; +extern afl_persistent_hook_fn hook; + +void persistent_init(void); + +/* Functions to be implemented by the different architectures */ +gboolean persistent_is_supported(void); + +void persistent_prologue(GumStalkerOutput *output); + +#endif + diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h index b7f25a97..8f0cee68 100644 --- a/frida_mode/include/prefetch.h +++ b/frida_mode/include/prefetch.h @@ -1,5 +1,11 @@ -void prefetch_init(); -void prefetch_start(GumStalker *stalker); +#ifndef _PREFETCH_H +#define _PREFETCH_H + +#include "frida-gum.h" + +void prefetch_init(void); void prefetch_write(void *addr); -void prefetch_read(GumStalker *stalker); +void prefetch_read(void); + +#endif diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index b9394dbc..f652eb8a 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -1,6 +1,11 @@ +#ifndef _RANGES_H +#define _RANGES_H + #include "frida-gum.h" -void ranges_init(GumStalker *stalker); +void ranges_init(void); gboolean range_is_excluded(gpointer address); +#endif + diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h new file mode 100644 index 00000000..186ead11 --- /dev/null +++ b/frida_mode/include/stalker.h @@ -0,0 +1,11 @@ +#ifndef _STALKER_H +#define _STALKER_H + +#include "frida-gum.h" + +void stalker_init(void); +GumStalker *stalker_get(void); +void stalker_start(void); + +#endif + diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h new file mode 100644 index 00000000..afd0b9c1 --- /dev/null +++ b/frida_mode/include/util.h @@ -0,0 +1,14 @@ +#ifndef _UTIL_H +#define _UTIL_H + +#include "frida-gum.h" + +#define UNUSED_PARAMETER(x) (void)(x) +#define IGNORED_RERURN(x) (void)!(x) + +guint64 util_read_address(char *key); + +guint64 util_read_num(char *key); + +#endif + diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c new file mode 100644 index 00000000..3fab1951 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog.c @@ -0,0 +1,87 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "util.h" + +#define DEFAULT_MMAP_MIN_ADDR (32UL << 10) + +extern struct cmp_map *__afl_cmp_map; + +static GArray *cmplog_ranges = NULL; + +static gboolean cmplog_range(const GumRangeDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + GumMemoryRange range = *details->range; + g_array_append_val(cmplog_ranges, range); + return TRUE; + +} + +static gint cmplog_sort(gconstpointer a, gconstpointer b) { + + return ((GumMemoryRange *)b)->base_address - + ((GumMemoryRange *)a)->base_address; + +} + +void cmplog_init(void) { + + if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + + cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); + gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL); + g_array_sort(cmplog_ranges, cmplog_sort); + + for (guint i = 0; i < cmplog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER + "X", + range->base_address, range->base_address + range->size); + + } + +} + +static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, + GumAddress outer_base, GumAddress outer_limit) { + + return (inner_base >= outer_base && inner_limit <= outer_limit); + +} + +gboolean cmplog_is_readable(void *addr, size_t size) { + + if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized"); + + /* + * The Linux kernel prevents mmap from allocating from the very bottom of the + * address space to mitigate NULL pointer dereference attacks. The exact size + * is set by sysctl by setting mmap_min_addr and 64k is suggested on most + * platforms with 32k on ARM systems. We therefore fail fast if the address + * is lower than this. This should avoid some overhead when functions are + * called where one of the parameters is a size, or a some other small value. + */ + if (GPOINTER_TO_SIZE(addr) < DEFAULT_MMAP_MIN_ADDR) { return false; } + + GumAddress inner_base = GUM_ADDRESS(addr); + GumAddress inner_limit = inner_base + size; + + for (guint i = 0; i < cmplog_ranges->len; i++) { + + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + GumAddress outer_base = range->base_address; + GumAddress outer_limit = outer_base + range->size; + + if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit)) + return true; + + } + + return false; + +} + diff --git a/frida_mode/src/cmplog/cmplog_arm.c b/frida_mode/src/cmplog/cmplog_arm.c new file mode 100644 index 00000000..5af28f3f --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__arm__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_arm64.c b/frida_mode/src/cmplog/cmplog_arm64.c new file mode 100644 index 00000000..187d0162 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm64.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__aarch64__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c new file mode 100644 index 00000000..9bf09ad5 --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -0,0 +1,346 @@ +#include "frida-gum.h" + +#include "debug.h" +#include "cmplog.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +typedef struct { + + x86_op_type type; + uint8_t size; + + union { + + x86_op_mem mem; + x86_reg reg; + int64_t imm; + + }; + +} cmplog_ctx_t; + +typedef struct { + + cmplog_ctx_t operand1; + cmplog_ctx_t operand2; + +} cmplog_pair_ctx_t; + +static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +static guint64 cmplog_read_mem(GumX64CpuContext *ctx, x86_op_mem *mem) { + + guint64 base = 0; + guint64 index = 0; + guint64 address; + + if (mem->base != X86_REG_INVALID) base = cmplog_read_reg(ctx, mem->base); + + if (mem->index != X86_REG_INVALID) index = cmplog_read_reg(ctx, mem->index); + + address = base + (index * mem->scale) + mem->disp; + return address; + +} + +static guint64 cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t * ctx) { + + switch (ctx->type) { + + case X86_OP_REG: + return cmplog_read_reg(context, ctx->reg); + case X86_OP_IMM: + return ctx->imm; + case X86_OP_MEM: + return cmplog_read_mem(context, &ctx->mem); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + +} + +static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + guint64 address = cmplog_read_reg(context, X86_REG_RIP); + guint64 rdi = cmplog_read_reg(context, X86_REG_RDI); + guint64 rsi = cmplog_read_reg(context, X86_REG_RSI); + + if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return; + + void *ptr1 = GSIZE_TO_POINTER(rdi); + void *ptr2 = GSIZE_TO_POINTER(rsi); + + if (!cmplog_is_readable(ptr1, 32) || !cmplog_is_readable(ptr2, 32)) return; + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx, + cs_x86_op * operand) { + + ctx->type = operand->type; + ctx->size = operand->size; + switch (operand->type) { + + case X86_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg)); + break; + case X86_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case X86_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void cmplog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand; + + if (instr->id != X86_INS_CALL) return; + + if (x86.op_count != 1) return; + + operand = &x86.operands[0]; + + if (operand->type == X86_OP_INVALID) return; + if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID) + return; + + gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL); + +} + +static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, + guint64 operand2, uint8_t size) { + + guint64 address = cmplog_read_reg(context, X86_REG_RIP); + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { + + cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + + if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); + + guint64 operand1 = cmplog_get_operand_value(context, &ctx->operand1); + guint64 operand2 = cmplog_get_operand_value(context, &ctx->operand2); + + cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); + +} + +static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand1, + cs_x86_op *operand2) { + + cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t)); + if (ctx == NULL) return; + + cmplog_instrument_put_operand(&ctx->operand1, operand1); + cmplog_instrument_put_operand(&ctx->operand2, operand2); + + gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx, + g_free); + +} + +static void cmplog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand1; + cs_x86_op *operand2; + + switch (instr->id) { + + case X86_INS_CMP: + case X86_INS_SUB: + break; + default: + return; + + } + + if (x86.op_count != 2) return; + + operand1 = &x86.operands[0]; + operand2 = &x86.operands[1]; + + if (operand1->type == X86_OP_INVALID) return; + if (operand2->type == X86_OP_INVALID) return; + + if ((operand1->type == X86_OP_MEM) && + (operand1->mem.segment != X86_REG_INVALID)) + return; + + if ((operand2->type == X86_OP_MEM) && + (operand2->mem.segment != X86_REG_INVALID)) + return; + + cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); + +} + +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + if (__afl_cmp_map == NULL) return; + + cmplog_instrument_call(instr, iterator); + cmplog_instrument_cmp_sub(instr, iterator); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x86.c b/frida_mode/src/cmplog/cmplog_x86.c new file mode 100644 index 00000000..2401180c --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_x86.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__i386__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c new file mode 100644 index 00000000..e71386a0 --- /dev/null +++ b/frida_mode/src/entry.c @@ -0,0 +1,50 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "entry.h" +#include "instrument.h" +#include "stalker.h" +#include "util.h" + +extern void __afl_manual_init(); + +guint64 entry_start = 0; + +static void entry_launch(void) { + + __afl_manual_init(); + + /* Child here */ + previous_pc = 0; + +} + +void entry_init(void) { + + entry_start = util_read_address("AFL_ENTRYPOINT"); + OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_start); + +} + +void entry_run(void) { + + if (entry_start == 0) { entry_launch(); } + +} + +static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) { + + UNUSED_PARAMETER(cpu_context); + UNUSED_PARAMETER(user_data); + entry_launch(); + +} + +void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL); + +} + diff --git a/frida_mode/src/instrument.c b/frida_mode/src/instrument.c deleted file mode 100644 index 22910062..00000000 --- a/frida_mode/src/instrument.c +++ /dev/null @@ -1,271 +0,0 @@ -#include "frida-gum.h" -#include "config.h" -#include "debug.h" -#include "prefetch.h" -#include "ranges.h" -#include "unistd.h" - -extern uint8_t *__afl_area_ptr; -extern u32 __afl_map_size; - -uint64_t __thread previous_pc = 0; -GumAddress current_log_impl = GUM_ADDRESS(0); - -static gboolean tracing = false; -static gboolean optimize = false; -static gboolean strict = false; - -#if defined(__x86_64__) -static const guint8 afl_log_code[] = { - - 0x9c, /* pushfq */ - 0x50, /* push rax */ - 0x51, /* push rcx */ - 0x52, /* push rdx */ - - 0x48, 0x8d, 0x05, 0x27, - 0x00, 0x00, 0x00, /* lea rax, sym._afl_area_ptr_ptr */ - 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ - 0x48, 0x8b, 0x00, /* mov rax, qword [rax] */ - 0x48, 0x8d, 0x0d, 0x22, - 0x00, 0x00, 0x00, /* lea rcx, sym.previous_pc */ - 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ - 0x48, 0x8b, 0x12, /* mov rdx, qword [rdx] */ - 0x48, 0x31, 0xfa, /* xor rdx, rdi */ - 0xfe, 0x04, 0x10, /* inc byte [rax + rdx] */ - 0x48, 0xd1, 0xef, /* shr rdi, 1 */ - 0x48, 0x8b, 0x01, /* mov rax, qword [rcx] */ - 0x48, 0x89, 0x38, /* mov qword [rax], rdi */ - - 0x5a, /* pop rdx */ - 0x59, /* pop rcx */ - 0x58, /* pop rax */ - 0x9d, /* popfq */ - - 0xc3, /* ret */ - - /* Read-only data goes here: */ - /* uint8_t** afl_area_ptr_ptr */ - /* uint64_t* afl_prev_loc_ptr */ - -}; - -void instrument_coverage_optimize(const cs_insn * instr, - GumStalkerOutput *output) { - - guint64 current_pc = instr->address; - guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); - area_offset &= MAP_SIZE - 1; - GumX86Writer *cw = output->writer.x86; - - if (current_log_impl == 0 || - !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || - !gum_x86_writer_can_branch_directly_between(cw->pc + 128, - current_log_impl)) { - - gconstpointer after_log_impl = cw->code + 1; - - gum_x86_writer_put_jmp_near_label(cw, after_log_impl); - - current_log_impl = cw->pc; - gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); - - uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - uint64_t *afl_prev_loc_ptr = &previous_pc; - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, - sizeof(afl_area_ptr_ptr)); - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, - sizeof(afl_prev_loc_ptr)); - - gum_x86_writer_put_label(cw, after_log_impl); - - } - - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - -GUM_RED_ZONE_SIZE); - gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); - gum_x86_writer_put_call_address(cw, current_log_impl); - gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - GUM_RED_ZONE_SIZE); - -} - -#elif defined(__aarch64__) -static const guint8 afl_log_code[] = { - - // __afl_area_ptr[current_pc ^ previous_pc]++; - // previous_pc = current_pc >> 1; - 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! - 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! - - // x0 = current_pc - 0xc1, 0x01, 0x00, 0x58, // ldr x1, #0x38, =&__afl_area_ptr - 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) - - 0xc2, 0x01, 0x00, 0x58, // ldr x2, #0x38, =&previous_pc - 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) - - // __afl_area_ptr[current_pc ^ previous_pc]++; - 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 - 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] - 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 - 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] - - // previous_pc = current_pc >> 1; - 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 - 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc - 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] - - 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 - 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 - 0xC0, 0x03, 0x5F, 0xD6, // ret - - // &afl_area_ptr_ptr - // &afl_prev_loc_ptr - -}; - -void instrument_coverage_optimize(const cs_insn * instr, - GumStalkerOutput *output) { - - guint64 current_pc = instr->address; - guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); - area_offset &= MAP_SIZE - 1; - GumArm64Writer *cw = output->writer.arm64; - - if (current_log_impl == 0 || - !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, - current_log_impl) || - !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, - current_log_impl)) { - - gconstpointer after_log_impl = cw->code + 1; - - gum_arm64_writer_put_b_label(cw, after_log_impl); - - current_log_impl = cw->pc; - gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); - - uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - uint64_t *afl_prev_loc_ptr = &previous_pc; - gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, - sizeof(afl_area_ptr_ptr)); - gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, - sizeof(afl_prev_loc_ptr)); - - gum_arm64_writer_put_label(cw, after_log_impl); - - } - - gum_arm64_writer_put_stp_reg_reg_reg_offset( - cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), - GUM_INDEX_PRE_ADJUST); - gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); - gum_arm64_writer_put_bl_imm(cw, current_log_impl); - gum_arm64_writer_put_ldp_reg_reg_reg_offset( - cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, - GUM_INDEX_POST_ADJUST); - -} - -#endif - -static void on_basic_block(GumCpuContext *context, gpointer user_data) { - - /* - * This function is performance critical as it is called to instrument every - * basic block. By moving our print buffer to a global, we avoid it affecting - * the critical path with additional stack adjustments if tracing is not - * enabled. If tracing is enabled, then we're printing a load of diagnostic - * information so this overhead is unlikely to be noticeable. - */ - static char buffer[200]; - int len; - guint64 current_pc = (guint64)user_data; - if (tracing) { - - /* Avoid any functions which may cause an allocation since the target app - * may already be running inside malloc and it isn't designed to be - * re-entrant on a single thread */ - len = snprintf(buffer, sizeof(buffer), - "current_pc: 0x%016" G_GINT64_MODIFIER - "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", - current_pc, previous_pc); - - write(STDOUT_FILENO, buffer, len + 1); - - } - - current_pc = (current_pc >> 4) ^ (current_pc << 8); - current_pc &= MAP_SIZE - 1; - - __afl_area_ptr[current_pc ^ previous_pc]++; - previous_pc = current_pc >> 1; - -} - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data) { - - const cs_insn *instr; - gboolean begin = TRUE; - while (gum_stalker_iterator_next(iterator, &instr)) { - - if (begin) { - - prefetch_write((void *)instr->address); - if (!strict || !range_is_excluded((void *)instr->address)) { - - if (optimize) { - - instrument_coverage_optimize(instr, output); - - } else { - - gum_stalker_iterator_put_callout(iterator, on_basic_block, - (gpointer)instr->address, NULL); - - } - - } - - begin = FALSE; - - } - - gum_stalker_iterator_keep(iterator); - - } - -} - -void instrument_init() { - - optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); - tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); - strict = (getenv("AFL_FRIDA_INST_STRICT") != NULL); - -#if !defined(__x86_64__) && !defined(__aarch64__) - optimize = false; -#endif - - OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); - OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); - OKF("Instrumentation - strict [%c]", strict ? 'X' : ' '); - - if (tracing && optimize) { - - FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); - - } - - if (__afl_map_size != 0x10000) { - - FATAL("Bad map size: 0x%08x", __afl_map_size); - - } - -} - diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c new file mode 100644 index 00000000..971f80c0 --- /dev/null +++ b/frida_mode/src/instrument/instrument.c @@ -0,0 +1,155 @@ +#include + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "entry.h" +#include "frida_cmplog.h" +#include "instrument.h" +#include "persistent.h" +#include "prefetch.h" +#include "ranges.h" +#include "stalker.h" +#include "util.h" + +static gboolean tracing = false; +static gboolean optimize = false; +static GumStalkerTransformer *transformer = NULL; + +__thread uint64_t previous_pc = 0; + +__attribute__((hot)) static void on_basic_block(GumCpuContext *context, + gpointer user_data) { + + UNUSED_PARAMETER(context); + /* + * This function is performance critical as it is called to instrument every + * basic block. By moving our print buffer to a global, we avoid it affecting + * the critical path with additional stack adjustments if tracing is not + * enabled. If tracing is enabled, then we're printing a load of diagnostic + * information so this overhead is unlikely to be noticeable. + */ + static char buffer[200]; + int len; + guint64 current_pc = (guint64)user_data; + uint8_t * cursor; + uint64_t value; + if (unlikely(tracing)) { + + /* Avoid any functions which may cause an allocation since the target app + * may already be running inside malloc and it isn't designed to be + * re-entrant on a single thread */ + len = snprintf(buffer, sizeof(buffer), + "current_pc: 0x%016" G_GINT64_MODIFIER + "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", + current_pc, previous_pc); + + IGNORED_RERURN(write(STDOUT_FILENO, buffer, len + 1)); + + } + + current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc &= MAP_SIZE - 1; + + cursor = &__afl_area_ptr[current_pc ^ previous_pc]; + value = *cursor; + + if (value == 0xff) { + + value = 1; + + } else { + + value++; + + } + + *cursor = value; + previous_pc = current_pc >> 1; + +} + +static void instr_basic_block(GumStalkerIterator *iterator, + GumStalkerOutput *output, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + const cs_insn *instr; + gboolean begin = TRUE; + while (gum_stalker_iterator_next(iterator, &instr)) { + + if (instr->address == entry_start) { entry_prologue(iterator, output); } + if (instr->address == persistent_start) { persistent_prologue(output); } + + if (begin) { + + prefetch_write((void *)instr->address); + if (!range_is_excluded((void *)instr->address)) { + + if (optimize) { + + instrument_coverage_optimize(instr, output); + + } else { + + gum_stalker_iterator_put_callout(iterator, on_basic_block, + (gpointer)instr->address, NULL); + + } + + } + + begin = FALSE; + + } + + if (!range_is_excluded((void *)instr->address)) { + + cmplog_instrument(instr, iterator); + + } + + gum_stalker_iterator_keep(iterator); + + } + +} + +void instrument_init(void) { + + optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); + tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + + if (!instrument_is_coverage_optimize_supported()) optimize = false; + + OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); + + if (tracing && optimize) { + + FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); + + } + + if (__afl_map_size != 0x10000) { + + FATAL("Bad map size: 0x%08x", __afl_map_size); + + } + + transformer = + gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + + cmplog_init(); + +} + +GumStalkerTransformer *instrument_get_transformer(void) { + + if (transformer == NULL) { FATAL("Instrumentation not initialized"); } + return transformer; + +} + diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c new file mode 100644 index 00000000..c2d720a7 --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -0,0 +1,23 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" + +#if defined(__arm__) + +gboolean instrument_is_coverage_optimize_supported(void) { + + return false; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + FATAL("Optimized coverage not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c new file mode 100644 index 00000000..fa3afb48 --- /dev/null +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -0,0 +1,97 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" + +#if defined(__aarch64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static const guint8 afl_log_code[] = { + + // __afl_area_ptr[current_pc ^ previous_pc]++; + // previous_pc = current_pc >> 1; + 0xE1, 0x0B, 0xBF, 0xA9, // stp x1, x2, [sp, -0x10]! + 0xE3, 0x13, 0xBF, 0xA9, // stp x3, x4, [sp, -0x10]! + + // x0 = current_pc + 0xe1, 0x01, 0x00, 0x58, // ldr x1, #0x3c, =&__afl_area_ptr + 0x21, 0x00, 0x40, 0xf9, // ldr x1, [x1] (=__afl_area_ptr) + + 0xe2, 0x01, 0x00, 0x58, // ldr x2, #0x3c, =&previous_pc + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2] (=previous_pc) + + // __afl_area_ptr[current_pc ^ previous_pc]++; + 0x42, 0x00, 0x00, 0xca, // eor x2, x2, x0 + 0x23, 0x68, 0x62, 0xf8, // ldr x3, [x1, x2] + 0x63, 0x04, 0x00, 0x91, // add x3, x3, #1 + 0x63, 0x00, 0x1f, 0x9a, // adc x3, x3, xzr + 0x23, 0x68, 0x22, 0xf8, // str x3, [x1, x2] + + // previous_pc = current_pc >> 1; + 0xe0, 0x07, 0x40, 0x8b, // add x0, xzr, x0, LSR #1 + 0xe2, 0x00, 0x00, 0x58, // ldr x2, #0x1c, =&previous_pc + 0x40, 0x00, 0x00, 0xf9, // str x0, [x2] + + 0xE3, 0x13, 0xc1, 0xA8, // ldp x3, x4, [sp], #0x10 + 0xE1, 0x0B, 0xc1, 0xA8, // ldp x1, x2, [sp], #0x10 + 0xC0, 0x03, 0x5F, 0xD6, // ret + + // &afl_area_ptr_ptr + // &afl_prev_loc_ptr + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumArm64Writer *cw = output->writer.arm64; + + if (current_log_impl == 0 || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc, + current_log_impl) || + !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_arm64_writer_put_b_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, + sizeof(afl_area_ptr_ptr)); + gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_arm64_writer_put_label(cw, after_log_impl); + + } + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset); + gum_arm64_writer_put_bl_imm(cw, current_log_impl); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c new file mode 100644 index 00000000..901f3bd0 --- /dev/null +++ b/frida_mode/src/instrument/instrument_x64.c @@ -0,0 +1,93 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" + +#if defined(__x86_64__) + +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static const guint8 afl_log_code[] = { + + // 0xcc, + + 0x9c, /* pushfq */ + 0x51, /* push rcx */ + 0x52, /* push rdx */ + + 0x48, 0x8b, 0x0d, 0x28, + 0x00, 0x00, 0x00, /* mov rcx, sym.&previous_pc */ + 0x48, 0x8b, 0x11, /* mov rdx, qword [rcx] */ + 0x48, 0x31, 0xfa, /* xor rdx, rdi */ + + 0x48, 0x03, 0x15, 0x13, + 0x00, 0x00, 0x00, /* add rdx, sym._afl_area_ptr_ptr */ + + 0x80, 0x02, 0x01, /* add byte ptr [rdx], 1 */ + 0x80, 0x12, 0x00, /* adc byte ptr [rdx], 0 */ + 0x48, 0xd1, 0xef, /* shr rdi, 1 */ + 0x48, 0x89, 0x39, /* mov qword [rcx], rdi */ + + 0x5a, /* pop rdx */ + 0x59, /* pop rcx */ + 0x9d, /* popfq */ + + 0xc3, /* ret */ + 0x90, 0x90, 0x90 /* nop pad */ + + /* Read-only data goes here: */ + /* uint8_t* __afl_area_ptr */ + /* uint64_t* &previous_pc */ + +}; + +gboolean instrument_is_coverage_optimize_supported(void) { + + return true; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); + + uint64_t *afl_prev_loc_ptr = &previous_pc; + gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr, + sizeof(__afl_area_ptr)); + gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, + sizeof(afl_prev_loc_ptr)); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -GUM_RED_ZONE_SIZE); + gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + GUM_RED_ZONE_SIZE); + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c new file mode 100644 index 00000000..5b8cbbba --- /dev/null +++ b/frida_mode/src/instrument/instrument_x86.c @@ -0,0 +1,23 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "instrument.h" + +#if defined(__i386__) + +gboolean instrument_is_coverage_optimize_supported(void) { + + return false; + +} + +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + FATAL("Optimized coverage not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/interceptor.c index ba05a80a..d2802752 100644 --- a/frida_mode/src/interceptor.c +++ b/frida_mode/src/interceptor.c @@ -1,4 +1,5 @@ #include "frida-gum.h" + #include "debug.h" #include "interceptor.h" @@ -9,8 +10,26 @@ void intercept(void *address, gpointer replacement, gpointer user_data) { gum_interceptor_begin_transaction(interceptor); GumReplaceReturn ret = gum_interceptor_replace(interceptor, address, replacement, user_data); - if (ret != GUM_ATTACH_OK) { FATAL("gum_interceptor_attach: %d", ret); } + if (ret != GUM_REPLACE_OK) { FATAL("gum_interceptor_attach: %d", ret); } gum_interceptor_end_transaction(interceptor); } +void unintercept(void *address) { + + GumInterceptor *interceptor = gum_interceptor_obtain(); + + gum_interceptor_begin_transaction(interceptor); + gum_interceptor_revert(interceptor, address); + gum_interceptor_end_transaction(interceptor); + gum_interceptor_flush(interceptor); + +} + +void unintercept_self(void) { + + GumInvocationContext *ctx = gum_interceptor_get_current_invocation(); + unintercept(ctx->function); + +} + diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c new file mode 100644 index 00000000..c5045533 --- /dev/null +++ b/frida_mode/src/lib/lib.c @@ -0,0 +1,176 @@ +#ifndef __APPLE__ + #include + #include + #include + #include + #include + #include + + #include "frida-gum.h" + + #include "debug.h" + + #include "lib.h" + + #if defined(__arm__) || defined(__i386__) + #define ELFCLASS ELFCLASS32 +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Addr Elf_Addr; + #elif defined(__aarch64__) || defined(__x86_64__) + #define ELFCLASS ELFCLASS64 +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Addr Elf_Addr; + #else + #error "Unsupported platform" + #endif + +typedef struct { + + gchar name[PATH_MAX + 1]; + gchar path[PATH_MAX + 1]; + GumAddress base_address; + gsize size; + +} lib_details_t; + +static guint64 text_base = 0; +static guint64 text_limit = 0; + +static gboolean lib_find_exe(const GumModuleDetails *details, + gpointer user_data) { + + lib_details_t *lib_details = (lib_details_t *)user_data; + + memcpy(lib_details->name, details->name, PATH_MAX); + memcpy(lib_details->path, details->path, PATH_MAX); + lib_details->base_address = details->range->base_address; + lib_details->size = details->range->size; + return FALSE; + +} + +static void lib_validate_hdr(Elf_Ehdr *hdr) { + + if (hdr->e_ident[0] != ELFMAG0) FATAL("Invalid e_ident[0]"); + if (hdr->e_ident[1] != ELFMAG1) FATAL("Invalid e_ident[1]"); + if (hdr->e_ident[2] != ELFMAG2) FATAL("Invalid e_ident[2]"); + if (hdr->e_ident[3] != ELFMAG3) FATAL("Invalid e_ident[3]"); + if (hdr->e_ident[4] != ELFCLASS) FATAL("Invalid class"); + +} + +static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) { + + Elf_Phdr *phdr; + gboolean found_preferred_base = FALSE; + Elf_Addr preferred_base; + Elf_Shdr *shdr; + Elf_Shdr *shstrtab; + char * shstr; + char * section_name; + Elf_Shdr *curr; + char text_name[] = ".text"; + + phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff); + for (size_t i = 0; i < hdr->e_phnum; i++) { + + if (phdr[i].p_type == PT_LOAD) { + + preferred_base = phdr[i].p_vaddr; + found_preferred_base = TRUE; + break; + + } + + } + + if (!found_preferred_base) { FATAL("Failed to find preferred load address"); } + + OKF("Image preferred load address 0x%016lx", preferred_base); + + shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff); + shstrtab = &shdr[hdr->e_shstrndx]; + shstr = (char *)hdr + shstrtab->sh_offset; + + OKF("shdr: %p", shdr); + OKF("shstrtab: %p", shstrtab); + OKF("shstr: %p", shstr); + + for (size_t i = 0; i < hdr->e_shnum; i++) { + + curr = &shdr[i]; + + if (curr->sh_name == 0) continue; + + section_name = &shstr[curr->sh_name]; + OKF("Section: %2lu - base: 0x%016lX size: 0x%016lX %s", i, curr->sh_addr, + curr->sh_size, section_name); + if (memcmp(section_name, text_name, sizeof(text_name)) == 0 && + text_base == 0) { + + text_base = lib_details->base_address + curr->sh_addr - preferred_base; + text_limit = text_base + curr->sh_size; + OKF("> text_addr: 0x%016lX", text_base); + OKF("> text_limit: 0x%016lX", text_limit); + + } + + } + +} + +static void lib_get_text_section(lib_details_t *details) { + + int fd = -1; + off_t len; + Elf_Ehdr *hdr; + + fd = open(details->path, O_RDONLY); + if (fd < 0) { FATAL("Failed to open %s", details->path); } + + len = lseek(fd, 0, SEEK_END); + + if (len == (off_t)-1) { FATAL("Failed to lseek %s", details->path); } + + OKF("len: %ld", len); + + hdr = (Elf_Ehdr *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (hdr == MAP_FAILED) { FATAL("Failed to map %s", details->path); } + + lib_validate_hdr(hdr); + lib_read_text_section(details, hdr); + + munmap(hdr, len); + close(fd); + +} + +void lib_init(void) { + + lib_details_t lib_details; + gum_process_enumerate_modules(lib_find_exe, &lib_details); + OKF("Executable: 0x%016lx - %s", lib_details.base_address, lib_details.path); + lib_get_text_section(&lib_details); + +} + +guint64 lib_get_text_base(void) { + + if (text_base == 0) FATAL("Lib not initialized"); + return text_base; + +} + +guint64 lib_get_text_limit(void) { + + if (text_limit == 0) FATAL("Lib not initialized"); + return text_limit; + +} + +#endif + diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c new file mode 100644 index 00000000..8f863861 --- /dev/null +++ b/frida_mode/src/lib/lib_apple.c @@ -0,0 +1,82 @@ +#ifdef __APPLE__ + #include "frida-gum.h" + + #include "debug.h" + + #include "lib.h" + #include "util.h" + +extern mach_port_t mach_task_self(); +extern void gum_darwin_enumerate_modules(mach_port_t task, + GumFoundModuleFunc func, + gpointer user_data); + +static guint64 text_base = 0; +static guint64 text_limit = 0; + +static gboolean lib_get_main_module(const GumModuleDetails *details, + gpointer user_data) { + + GumDarwinModule **ret = (GumDarwinModule **)user_data; + GumDarwinModule * module = gum_darwin_module_new_from_memory( + details->path, mach_task_self(), details->range->base_address, + GUM_DARWIN_MODULE_FLAGS_NONE, NULL); + + OKF("Found main module: %s", module->name); + + *ret = module; + + return FALSE; + +} + +gboolean lib_get_text_section(const GumDarwinSectionDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + static size_t idx = 0; + char text_name[] = "__text"; + + OKF("Section: %2lu - base: 0x%016" G_GINT64_MODIFIER + "X size: 0x%016" G_GINT64_MODIFIER "X %s", + idx++, details->vm_address, details->vm_address + details->size, + details->section_name); + + if (memcmp(details->section_name, text_name, sizeof(text_name)) == 0 && + text_base == 0) { + + text_base = details->vm_address; + text_limit = details->vm_address + details->size; + OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base); + OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit); + + } + + return TRUE; + +} + +void lib_init(void) { + + GumDarwinModule *module = NULL; + gum_darwin_enumerate_modules(mach_task_self(), lib_get_main_module, &module); + gum_darwin_module_enumerate_sections(module, lib_get_text_section, NULL); + +} + +guint64 lib_get_text_base(void) { + + if (text_base == 0) FATAL("Lib not initialized"); + return text_base; + +} + +guint64 lib_get_text_limit(void) { + + if (text_limit == 0) FATAL("Lib not initialized"); + return text_limit; + +} + +#endif + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 7505c2f9..e031dbed 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -10,13 +10,19 @@ #endif #include "frida-gum.h" + #include "config.h" #include "debug.h" -#include "interceptor.h" +#include "entry.h" #include "instrument.h" +#include "interceptor.h" +#include "lib.h" +#include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "stalker.h" +#include "util.h" #ifdef __APPLE__ extern mach_port_t mach_task_self(); @@ -30,16 +36,11 @@ extern int __libc_start_main(int *(main)(int, char **, char **), int argc, typedef int *(*main_fn_t)(int argc, char **argv, char **envp); -static main_fn_t main_fn = NULL; -static GumStalker * stalker = NULL; -static GumMemoryRange code_range = {0}; - -extern void __afl_manual_init(); -extern __thread uint64_t previous_pc; +static main_fn_t main_fn = NULL; -static int on_fork() { +static int on_fork(void) { - prefetch_read(stalker); + prefetch_read(); return fork(); } @@ -47,11 +48,17 @@ static int on_fork() { #ifdef __APPLE__ static void on_main_os(int argc, char **argv, char **envp) { + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + UNUSED_PARAMETER(envp); + } #else static void on_main_os(int argc, char **argv, char **envp) { + UNUSED_PARAMETER(argc); + /* Personality doesn't affect the current process, it only takes effect on * evec */ int persona = personality(ADDR_NO_RANDOMIZE); @@ -70,37 +77,43 @@ static void on_main_os(int argc, char **argv, char **envp) { static int *on_main(int argc, char **argv, char **envp) { - on_main_os(argc, argv, envp); + void *fork_addr; - stalker = gum_stalker_new(); - if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + on_main_os(argc, argv, envp); - gum_stalker_set_trust_threshold(stalker, 0); + unintercept_self(); - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + stalker_init(); + lib_init(); + entry_init(); instrument_init(); + persistent_init(); prefetch_init(); - ranges_init(stalker); + ranges_init(); - intercept(fork, on_fork, stalker); + fork_addr = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); + intercept(fork_addr, on_fork, NULL); - gum_stalker_follow_me(stalker, transformer, NULL); - gum_stalker_deactivate(stalker); + stalker_start(); + entry_run(); - __afl_manual_init(); + return main_fn(argc, argv, envp); - /* Child here */ - previous_pc = 0; - prefetch_start(stalker); - main_fn(argc, argv, envp); - _exit(0); +} + +#if defined(EMBEDDED) +extern int *main(int argc, char **argv, char **envp); + +static void intercept_main(void) { + + main_fn = main; + intercept(main, on_main, NULL); } -#ifdef __APPLE__ -static void intercept_main() { +#elif defined(__APPLE__) +static void intercept_main(void) { mach_port_t task = mach_task_self(); OKF("Task Id: %u", task); @@ -119,13 +132,14 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc, void(*stack_end)) { main_fn = main; + unintercept_self(); intercept(main, on_main, NULL); return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); } -static void intercept_main() { +static void intercept_main(void) { intercept(__libc_start_main, on_libc_start_main, NULL); @@ -133,7 +147,7 @@ static void intercept_main() { #endif -__attribute__((constructor)) static void init() { +__attribute__((constructor)) static void init(void) { gum_init_embedded(); if (!gum_stalker_is_supported()) { diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c new file mode 100644 index 00000000..918ff153 --- /dev/null +++ b/frida_mode/src/persistent/persistent.c @@ -0,0 +1,65 @@ +#include + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +int __afl_sharedmem_fuzzing = 0; +afl_persistent_hook_fn hook = NULL; +guint64 persistent_start = 0; +guint64 persistent_count = 0; + +void persistent_init(void) { + + char *hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); + + persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); + persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); + + if (persistent_count != 0 && persistent_start == 0) + FATAL( + "AFL_FRIDA_PERSISTENT_ADDR must be specified if " + "AFL_FRIDA_PERSISTENT_CNT is"); + + if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; + + if (persistent_count != 0 && persistent_count < 100) + WARNF("Persistent count out of recommended range (<100)"); + + if (persistent_start != 0 && !persistent_is_supported()) + FATAL("Persistent mode not supported on this architecture"); + + OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_start == 0 ? ' ' : 'X', persistent_start); + OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)", + persistent_start == 0 ? ' ' : 'X', persistent_count); + OKF("Instrumentation - hook [%s]", hook_name); + + if (hook_name != NULL) { + + void *hook_obj = dlopen(hook_name, RTLD_NOW); + if (hook_obj == NULL) + FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name); + + int (*afl_persistent_hook_init_ptr)(void) = + dlsym(hook_obj, "afl_persistent_hook_init"); + if (afl_persistent_hook_init_ptr == NULL) + FATAL("Failed to find afl_persistent_hook_init in %s", hook_name); + + if (afl_persistent_hook_init_ptr() == 0) + FATAL("afl_persistent_hook_init returned a failure"); + + hook = (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook"); + if (hook == NULL) + FATAL("Failed to find afl_persistent_hook in %s", hook_name); + + __afl_sharedmem_fuzzing = 1; + + } + +} + diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c new file mode 100644 index 00000000..bc021ff3 --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -0,0 +1,72 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +#if defined(__arm__) + +struct arm_regs { + + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; + + union { + + uint32_t r11; + uint32_t fp; + + }; + + union { + + uint32_t r12; + uint32_t ip; + + }; + + union { + + uint32_t r13; + uint32_t sp; + + }; + + union { + + uint32_t r14; + uint32_t lr; + + }; + + union { + + uint32_t r15; + uint32_t pc; + + }; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16]; + uint32_t vfp_xregs[16]; + +}; + +typedef struct arm_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c new file mode 100644 index 00000000..c198da69 --- /dev/null +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -0,0 +1,115 @@ +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" + +#include "instrument.h" +#include "util.h" + +#if defined(__aarch64__) + +struct arm64_regs { + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; + + union { + + uint64_t x11; + uint32_t fp_32; + + }; + + union { + + uint64_t x12; + uint32_t ip_32; + + }; + + union { + + uint64_t x13; + uint32_t sp_32; + + }; + + union { + + uint64_t x14; + uint32_t lr_32; + + }; + + union { + + uint64_t x15; + uint32_t pc_32; + + }; + + union { + + uint64_t x16; + uint64_t ip0; + + }; + + union { + + uint64_t x17; + uint64_t ip1; + + }; + + uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; + + union { + + uint64_t x29; + uint64_t fp; + + }; + + union { + + uint64_t x30; + uint64_t lr; + + }; + + union { + + uint64_t x31; + uint64_t sp; + + }; + + // the zero register is not saved here ofc + + uint64_t pc; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16 * 16]; + uint8_t vfp_pregs[17][32]; + uint32_t vfp_xregs[16]; + +}; + +typedef struct arm64_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c new file mode 100644 index 00000000..49f1988c --- /dev/null +++ b/frida_mode/src/persistent/persistent_x64.c @@ -0,0 +1,342 @@ +#include "frida-gum.h" + +#include "config.h" + +#include "instrument.h" +#include "persistent.h" + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +typedef struct x86_64_regs arch_api_regs; + +static arch_api_regs saved_regs = {0}; +static void * saved_return = NULL; + +gboolean persistent_is_supported(void) { + + return true; + +} + +static void instrument_persitent_save_regs(GumX86Writer * cw, + struct x86_64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + /* Should be pushing FPU here, but meh */ + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1), + GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2), + GUM_REG_RCX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3), + GUM_REG_RDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4), + GUM_REG_RDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5), + GUM_REG_RSI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6), + GUM_REG_RBP); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7), + GUM_REG_R8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8), + GUM_REG_R9); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9), + GUM_REG_R10); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10), + GUM_REG_R11); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11), + GUM_REG_R12); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12), + GUM_REG_R13); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13), + GUM_REG_R14); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14), + GUM_REG_R15); + + /* Store RIP */ + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX, + GUM_ADDRESS(persistent_start)); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15), + GUM_REG_RBX); + + /* Store adjusted RSP */ + gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP); + + /* RED_ZONE + Saved flags, RAX, alignment */ + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX, + GUM_RED_ZONE_SIZE + (0x8 * 3)); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16), + GUM_REG_RBX); + + /* Save the flags */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17), + GUM_REG_RBX); + + /* Save the RAX */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0), + GUM_REG_RBX); + + /* Pop the saved values */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_persitent_restore_regs(GumX86Writer * cw, + struct x86_64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX, + (0x8 * 2)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX, + (0x8 * 3)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX, + (0x8 * 4)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX, + (0x8 * 5)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX, + (0x8 * 6)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX, + (0x8 * 7)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX, + (0x8 * 8)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX, + (0x8 * 9)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX, + (0x8 * 10)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX, + (0x8 * 11)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX, + (0x8 * 12)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX, + (0x8 * 13)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX, + (0x8 * 14)); + + /* Don't restore RIP or RSP */ + + /* Restore RBX, RAX & Flags */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 1)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 0)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, + (0x8 * 17)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_popfx(cw); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, + GUM_RED_ZONE_SIZE + 0x10); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, 0, GUM_REG_RBX); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + /* Place holder for ret */ + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RAX, GUM_REG_RAX, 0); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RSP, 0x8, GUM_REG_RAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_ret_imm(cw, GUM_RED_ZONE_SIZE); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +static void instrument_afl_persistent_loop(GumX86Writer *cw) { + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); + gum_x86_writer_put_test_reg_reg(cw, GUM_REG_RAX, GUM_REG_RAX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +static void persistent_prologue_hook(GumX86Writer * cw, + struct x86_64_regs *regs) { + + if (hook == NULL) return; + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX, + GUM_ADDRESS(&__afl_fuzz_len)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff); + gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); + + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, + GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, + GUM_REG_RDX, GUM_ARG_REGISTER, GUM_REG_RCX); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + +void persistent_prologue(GumStalkerOutput *output) { + + /* + * SAVE REGS + * SAVE RET + * POP RET + * loop: + * CALL instrument_afl_persistent_loop + * TEST EAX, EAX + * JZ end: + * call hook (optionally) + * RESTORE REGS + * call original + * jmp loop: + * + * end: + * JMP SAVED RET + * + * original: + * INSTRUMENTED PERSISTENT FUNC + */ + + GumX86Writer *cw = output->writer.x86; + + gconstpointer loop = cw->code + 1; + // gum_x86_writer_put_breakpoint(cw); + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* Stash and pop the return value */ + instrument_save_ret(cw, &saved_return); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8)); + + /* loop: */ + gum_x86_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY); + + /* Optionally call the persistent hook */ + persistent_prologue_hook(cw, &saved_regs); + + instrument_persitent_restore_regs(cw, &saved_regs); + gconstpointer original = cw->code + 1; + /* call original */ + gum_x86_writer_put_call_near_label(cw, original); + /* jmp loop */ + gum_x86_writer_put_jmp_near_label(cw, loop); + + /* done: */ + gum_x86_writer_put_label(cw, done); + + instrument_jump_ret(cw, &saved_return); + + /* original: */ + gum_x86_writer_put_label(cw, original); + + gum_x86_writer_flush(cw); + +} + +#endif + diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c new file mode 100644 index 00000000..9d39c4e9 --- /dev/null +++ b/frida_mode/src/persistent/persistent_x86.c @@ -0,0 +1,55 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "persistent.h" +#include "util.h" + +#if defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +typedef struct x86_regs arch_api_regs; + +gboolean persistent_is_supported(void) { + + return false; + +} + +void persistent_prologue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 64633c1c..65c09fba 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -3,9 +3,12 @@ #include #include "frida-gum.h" -#include "prefetch.h" + #include "debug.h" +#include "prefetch.h" +#include "stalker.h" + #define TRUST 0 #define PREFETCH_SIZE 65536 #define PREFETCH_ENTRIES ((PREFETCH_SIZE - sizeof(size_t)) / sizeof(void *)) @@ -49,8 +52,9 @@ void prefetch_write(void *addr) { /* * Read the IPC region one block at the time and prefetch it */ -void prefetch_read(GumStalker *stalker) { +void prefetch_read(void) { + GumStalker *stalker = stalker_get(); if (prefetch_data == NULL) return; for (size_t i = 0; i < prefetch_data->count; i++) { @@ -68,7 +72,7 @@ void prefetch_read(GumStalker *stalker) { } -void prefetch_init() { +void prefetch_init(void) { g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); @@ -106,16 +110,3 @@ void prefetch_init() { } -__attribute__((noinline)) static void prefetch_activation() { - - asm volatile(""); - -} - -void prefetch_start(GumStalker *stalker) { - - gum_stalker_activate(stalker, prefetch_activation); - prefetch_activation(); - -} - diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 49ef5a62..e3f09f9e 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -1,9 +1,12 @@ -// 0x123-0x321 -// module.so +#include "frida-gum.h" -#include "ranges.h" #include "debug.h" +#include "lib.h" +#include "ranges.h" +#include "stalker.h" +#include "util.h" + #define MAX_RANGES 20 typedef struct { @@ -14,15 +17,11 @@ typedef struct { } convert_name_ctx_t; -typedef struct { - - GumStalker *stalker; - GArray * array; - -} include_range_ctx_t; - -GArray * ranges = NULL; -gboolean exclude_ranges = false; +GArray *module_ranges = NULL; +GArray *libs_ranges = NULL; +GArray *include_ranges = NULL; +GArray *exclude_ranges = NULL; +GArray *ranges = NULL; static void convert_address_token(gchar *token, GumMemoryRange *range) { @@ -159,236 +158,417 @@ static void convert_token(gchar *token, GumMemoryRange *range) { } -static gboolean include_ranges(const GumRangeDetails *details, - gpointer user_data) { +gint range_sort(gconstpointer a, gconstpointer b) { - include_range_ctx_t *ctx = (include_range_ctx_t *)user_data; - GArray * array = (GArray *)ctx->array; - GumAddress base = details->range->base_address; - GumAddress limit = details->range->base_address + details->range->size; + return ((GumMemoryRange *)a)->base_address - + ((GumMemoryRange *)b)->base_address; - OKF("Range for inclusion 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x", - base, limit); +} - for (int i = 0; i < array->len; i++) { +static gboolean print_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - GumMemoryRange *range = &g_array_index(array, GumMemoryRange, i); - GumAddress range_base = range->base_address; - GumAddress range_limit = range->base_address + range->size; + UNUSED_PARAMETER(user_data); + if (details->file == NULL) { - /* Before the region */ - if (range_limit < base) { continue; } + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", + details->range->base_address, + details->range->base_address + details->range->size); - /* After the region */ - if (range_base > limit) { + } else { - GumMemoryRange exclude = {.base_address = base, .size = limit - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER - "x", - base, limit); - gum_stalker_exclude(ctx->stalker, &exclude); - return true; + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER + "X %s(0x%016" G_GINT64_MODIFIER "x)", + details->range->base_address, + details->range->base_address + details->range->size, + details->file->path, details->file->offset); - } + } - /* Overlap the start of the region */ - if (range_base < base) { + return true; - /* Range contains the region */ - if (range_limit > limit) { +} - return true; +static void print_ranges(char *key, GArray *ranges) { - } else { + OKF("Range: %s Length: %d", key, ranges->len); + for (guint i = 0; i < ranges->len; i++) { - base = range_limit; - continue; + GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); + GumAddress curr_limit = curr->base_address + curr->size; + OKF("Range: %s Idx: %3d - 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + key, i, curr->base_address, curr_limit); - } + } - /* Overlap the end of the region */ +} - } else { +static gboolean collect_module_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { - GumMemoryRange exclude = {.base_address = base, - .size = range_base - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER - "x", - base, range_base); - gum_stalker_exclude(ctx->stalker, &exclude); - /* Extend past the end of the region */ - if (range_limit >= limit) { + GArray * ranges = (GArray *)user_data; + GumMemoryRange range = *details->range; + g_array_append_val(ranges, range); + return TRUE; - return true; +} - /* Contained within the region */ +static GArray *collect_module_ranges(void) { - } else { + GArray *result; + result = g_array_new(false, false, sizeof(GumMemoryRange)); + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, + collect_module_ranges_callback, result); + print_ranges("Modules", result); + return result; - base = range_limit; - continue; +} - } +static GArray *collect_ranges(char *env_key) { - } + char * env_val; + gchar ** tokens; + int token_count; + GumMemoryRange range; + int i; + GArray * result; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + + env_val = getenv(env_key); + if (env_val == NULL) return result; + + tokens = g_strsplit(env_val, ",", MAX_RANGES); + + for (token_count = 0; tokens[token_count] != NULL; token_count++) + ; + + for (i = 0; i < token_count; i++) { + + convert_token(tokens[i], &range); + g_array_append_val(result, range); } - GumMemoryRange exclude = {.base_address = base, .size = limit - base}; - OKF("\t Excluding 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", - base, limit); - gum_stalker_exclude(ctx->stalker, &exclude); - return true; + g_array_sort(result, range_sort); -} + /* Check for overlaps */ + for (i = 1; i < token_count; i++) { -gint range_sort(gconstpointer a, gconstpointer b) { + GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { - return ((GumMemoryRange *)a)->base_address - - ((GumMemoryRange *)b)->base_address; + FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER + "x-0x%016" G_GINT64_MODIFIER "x", + prev->base_address, prev_limit, curr->base_address, curr_limit); + + } + + } + + print_ranges(env_key, result); + + g_strfreev(tokens); + + return result; } -static gboolean print_ranges(const GumRangeDetails *details, - gpointer user_data) { +static GArray *collect_libs_ranges(void) { - if (details->file == NULL) { + GArray * result; + GumMemoryRange range; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", - details->range->base_address, - details->range->base_address + details->range->size); + if (getenv("AFL_INST_LIBS") == NULL) { + + range.base_address = lib_get_text_base(); + range.size = lib_get_text_limit() - lib_get_text_base(); } else { - OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER - "X %s(0x%016" G_GINT64_MODIFIER "x)", - details->range->base_address, - details->range->base_address + details->range->size, - details->file->path, details->file->offset); + range.base_address = 0; + range.size = G_MAXULONG; } + g_array_append_val(result, range); + + print_ranges("AFL_INST_LIBS", result); + + return result; + +} + +static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra, + GumMemoryRange *rb) { + + GumAddress rab = ra->base_address; + GumAddress ral = rab + ra->size; + + GumAddress rbb = rb->base_address; + GumAddress rbl = rbb + rb->size; + + GumAddress rrb = 0; + GumAddress rrl = 0; + + rr->base_address = 0; + rr->size = 0; + + /* ra is before rb */ + if (ral < rbb) { return false; } + + /* ra is after rb */ + if (rab > rbl) { return true; } + + /* The largest of the two base addresses */ + rrb = rab > rbb ? rab : rbb; + + /* The smallest of the two limits */ + rrl = ral < rbl ? ral : rbl; + + rr->base_address = rrb; + rr->size = rrl - rrb; return true; } -void ranges_init(GumStalker *stalker) { +static GArray *intersect_ranges(GArray *a, GArray *b) { - char * showmaps; - char * include; - char * exclude; - char * list; - gchar ** tokens; - int token_count; - GumMemoryRange range; + GArray * result; + GumMemoryRange *ra; + GumMemoryRange *rb; + GumMemoryRange ri; - int i; + result = g_array_new(false, false, sizeof(GumMemoryRange)); - showmaps = getenv("AFL_FRIDA_DEBUG_MAPS"); - include = getenv("AFL_FRIDA_INST_RANGES"); - exclude = getenv("AFL_FRIDA_EXCLUDE_RANGES"); + for (guint i = 0; i < a->len; i++) { - if (showmaps) { + ra = &g_array_index(a, GumMemoryRange, i); + for (guint j = 0; j < b->len; j++) { - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges, NULL); + rb = &g_array_index(b, GumMemoryRange, j); - } + if (!intersect_range(&ri, ra, rb)) { break; } + + if (ri.size == 0) { continue; } - if (include != NULL && exclude != NULL) { + g_array_append_val(result, ri); - FATAL( - "Cannot specifify both AFL_FRIDA_INST_RANGES and " - "AFL_FRIDA_EXCLUDE_RANGES"); + } } - if (include == NULL && exclude == NULL) { return; } + return result; - list = include == NULL ? exclude : include; - exclude_ranges = include == NULL ? true : false; +} - tokens = g_strsplit(list, ",", MAX_RANGES); +static GArray *subtract_ranges(GArray *a, GArray *b) { - for (token_count = 0; tokens[token_count] != NULL; token_count++) - ; + GArray * result; + GumMemoryRange *ra; + GumAddress ral; + GumMemoryRange *rb; + GumMemoryRange ri; + GumMemoryRange rs; - ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), token_count); + result = g_array_new(false, false, sizeof(GumMemoryRange)); - for (i = 0; i < token_count; i++) { + for (guint i = 0; i < a->len; i++) { - convert_token(tokens[i], &range); - g_array_append_val(ranges, range); + ra = &g_array_index(a, GumMemoryRange, i); + ral = ra->base_address + ra->size; + for (guint j = 0; j < b->len; j++) { + + rb = &g_array_index(b, GumMemoryRange, j); + + /* + * If rb is after ra, we have no more possible intersections and we can + * simply keep the remaining range + */ + if (!intersect_range(&ri, ra, rb)) { break; } + + /* + * If there is no intersection, then rb must be before ra, so we must + * continue + */ + if (ri.size == 0) { continue; } + + /* + * If the intersection is part way through the range, then we keep the + * start of the range + */ + if (ra->base_address < ri.base_address) { + + rs.base_address = ra->base_address; + rs.size = ri.base_address - ra->base_address; + g_array_append_val(result, rs); + + } + + /* + * If the intersection extends past the limit of the range, then we should + * continue with the next range + */ + if ((ri.base_address + ri.size) > ral) { + + ra->base_address = ral; + ra->size = 0; + break; + + } + + /* + * Otherwise we advance the base of the range to the end of the + * intersection and continue with the remainder of the range + */ + ra->base_address = ri.base_address + ri.size; + ra->size = ral - ra->base_address; + + } + + /* + * When we have processed all the possible intersections, we add what is + * left + */ + if (ra->size != 0) g_array_append_val(result, *ra); } - g_array_sort(ranges, range_sort); + return result; - /* Check for overlaps */ - for (i = 1; i < token_count; i++) { +} - GumMemoryRange *prev = &g_array_index(ranges, GumMemoryRange, i - 1); - GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); - GumAddress prev_limit = prev->base_address + prev->size; - GumAddress curr_limit = curr->base_address + curr->size; - if (prev_limit > curr->base_address) { +static GArray *merge_ranges(GArray *a) { - FATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER - "x-0x%016" G_GINT64_MODIFIER "x", - prev->base_address, prev_limit, curr->base_address, curr_limit); + GArray * result; + GumMemoryRange rp; + GumMemoryRange *r; + + result = g_array_new(false, false, sizeof(GumMemoryRange)); + if (a->len == 0) return result; + + rp = g_array_index(a, GumMemoryRange, 0); + + for (guint i = 1; i < a->len; i++) { + + r = &g_array_index(a, GumMemoryRange, i); + + if (rp.base_address + rp.size == r->base_address) { + + rp.size += r->size; + + } else { + + g_array_append_val(result, rp); + rp.base_address = r->base_address; + rp.size = r->size; + continue; } } - for (i = 0; i < token_count; i++) { + g_array_append_val(result, rp); - GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); - GumAddress curr_limit = curr->base_address + curr->size; - OKF("Range %3d - 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", - i, curr->base_address, curr_limit); + return result; + +} + +void ranges_init(void) { + + GumMemoryRange ri; + GArray * step1; + GArray * step2; + GArray * step3; + GArray * step4; + GumMemoryRange *r; + GumStalker * stalker; + + if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, + NULL); } - if (include == NULL) { + module_ranges = collect_module_ranges(); + libs_ranges = collect_libs_ranges(); + include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); - for (i = 0; i < token_count; i++) { + /* If include ranges is empty, then assume everything is included */ + if (include_ranges->len == 0) { - gum_stalker_exclude(stalker, &g_array_index(ranges, GumMemoryRange, i)); + ri.base_address = 0; + ri.size = G_MAXULONG; + g_array_append_val(include_ranges, ri); - } + } - } else { + exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); - include_range_ctx_t ctx = {.stalker = stalker, .array = ranges}; - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, include_ranges, &ctx); + /* Intersect with .text section of main executable unless AFL_INST_LIBS */ + step1 = intersect_ranges(module_ranges, libs_ranges); + print_ranges("step1", step1); + + /* Intersect with AFL_FRIDA_INST_RANGES */ + step2 = intersect_ranges(step1, include_ranges); + print_ranges("step2", step2); + + /* Subtract AFL_FRIDA_EXCLUDE_RANGES */ + step3 = subtract_ranges(step2, exclude_ranges); + print_ranges("step3", step3); + + /* + * After step3, we have the total ranges to be instrumented, we now subtract + * that from the original ranges of the modules to configure stalker. + */ + + step4 = subtract_ranges(module_ranges, step3); + print_ranges("step4", step4); + + ranges = merge_ranges(step4); + print_ranges("final", ranges); + + stalker = stalker_get(); + + for (guint i = 0; i < ranges->len; i++) { + + r = &g_array_index(ranges, GumMemoryRange, i); + gum_stalker_exclude(stalker, r); } - g_strfreev(tokens); + g_array_free(step4, TRUE); + g_array_free(step3, TRUE); + g_array_free(step2, TRUE); + g_array_free(step1, TRUE); } gboolean range_is_excluded(gpointer address) { - int i; GumAddress test = GUM_ADDRESS(address); if (ranges == NULL) { return false; } - for (i = 0; i < ranges->len; i++) { + for (guint i = 0; i < ranges->len; i++) { GumMemoryRange *curr = &g_array_index(ranges, GumMemoryRange, i); GumAddress curr_limit = curr->base_address + curr->size; - if (test < curr->base_address) { return !exclude_ranges; } + if (test < curr->base_address) { return false; } - if (test < curr_limit) { return exclude_ranges; } + if (test < curr_limit) { return true; } } - return !exclude_ranges; + return false; } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c new file mode 100644 index 00000000..81973e9c --- /dev/null +++ b/frida_mode/src/stalker.c @@ -0,0 +1,30 @@ +#include "debug.h" + +#include "instrument.h" +#include "stalker.h" + +static GumStalker *stalker = NULL; + +void stalker_init(void) { + + stalker = gum_stalker_new(); + if (stalker == NULL) { FATAL("Failed to initialize stalker"); } + + gum_stalker_set_trust_threshold(stalker, 0); + +} + +GumStalker *stalker_get(void) { + + if (stalker == NULL) { FATAL("Stalker uninitialized"); } + return stalker; + +} + +void stalker_start(void) { + + GumStalkerTransformer *transformer = instrument_get_transformer(); + gum_stalker_follow_me(stalker, transformer, NULL); + +} + diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c new file mode 100644 index 00000000..86b94970 --- /dev/null +++ b/frida_mode/src/util.c @@ -0,0 +1,67 @@ +#include "util.h" + +#include "debug.h" + +guint64 util_read_address(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + if (!g_str_has_prefix(value_str, "0x")) { + + FATAL("Invalid address should have 0x prefix: %s\n", value_str); + + } + + char *value_str2 = &value_str[2]; + + for (char *c = value_str2; *c != '\0'; c++) { + + if (!g_ascii_isxdigit(*c)) { + + FATAL("Invalid address not formed of hex digits: %s ('%c')\n", value_str, + *c); + + } + + } + + guint64 value = g_ascii_strtoull(value_str2, NULL, 16); + if (value == 0) { + + FATAL("Invalid address failed hex conversion: %s\n", value_str2); + + } + + return value; + +} + +guint64 util_read_num(char *key) { + + char *value_str = getenv(key); + + if (value_str == NULL) { return 0; } + + for (char *c = value_str; *c != '\0'; c++) { + + if (!g_ascii_isdigit(*c)) { + + FATAL("Invalid address not formed of decimal digits: %s\n", value_str); + + } + + } + + guint64 value = g_ascii_strtoull(value_str, NULL, 10); + if (value == 0) { + + FATAL("Invalid address failed numeric conversion: %s\n", value_str); + + } + + return value; + +} + diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile new file mode 100644 index 00000000..c203fc5e --- /dev/null +++ b/frida_mode/test/cmplog/GNUmakefile @@ -0,0 +1,66 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../)/ +BUILD_DIR:=$(PWD)build/ + +TEST_CMPLOG_DIR:=$(ROOT)qemu_mode/libcompcov/ +TEST_CMPLOG_OBJ=$(TEST_CMPLOG_DIR)compcovtest + +TEST_BIN:=$(PWD)../../build/test + + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +CMP_LOG_INPUT:=$(TEST_DATA_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000555555554000) +endif + +.PHONY: all clean qemu frida + +all: + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(CMP_LOG_INPUT): | $(TEST_DATA_DIR) + truncate -s 64 $@ + +$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_DIR)compcovtest.cc + make -C $(TEST_CMPLOG_DIR) compcovtest + +qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -c 0 \ + -l 3AT \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + XAFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -c 0 \ + -l 3AT \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + +clean: + rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/cmplog/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/cmplog/get_section_addrs.py b/frida_mode/test/cmplog/get_section_addrs.py new file mode 100755 index 00000000..f648808b --- /dev/null +++ b/frida_mode/test/cmplog/get_section_addrs.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +import argparse +from elftools.elf.elffile import ELFFile + + +def process_file(file, section, base): + with open(file, "rb") as f: + for sect in ELFFile(f).iter_sections(): + if sect.name == section: + start = base + sect.header["sh_offset"] + end = start + sect.header["sh_size"] + print("0x%016x-0x%016x" % (start, end)) + return + + print("Section '%s' not found in '%s'" % (section, file)) + + +def hex_value(x): + return int(x, 16) + + +def main(): + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument( + "-f", "--file", dest="file", type=str, help="elf file name", required=True + ) + parser.add_argument( + "-s", + "--section", + dest="section", + type=str, + help="elf section name", + required=True, + ) + parser.add_argument( + "-b", + "--base", + dest="base", + type=hex_value, + help="elf base address", + required=True, + ) + + args = parser.parse_args() + process_file(args.file, args.section, args.base) + + +if __name__ == "__main__": + main() diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile new file mode 100644 index 00000000..891827eb --- /dev/null +++ b/frida_mode/test/entry_point/GNUmakefile @@ -0,0 +1,61 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) +endif + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida_entry: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ \ No newline at end of file diff --git a/frida_mode/test/entry_point/Makefile b/frida_mode/test/entry_point/Makefile new file mode 100644 index 00000000..3b41b94e --- /dev/null +++ b/frida_mode/test/entry_point/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +frida_entry: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/entry_point/testinstr.c b/frida_mode/test/entry_point/testinstr.c new file mode 100644 index 00000000..a6c655f9 --- /dev/null +++ b/frida_mode/test/entry_point/testinstr.c @@ -0,0 +1,119 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + usleep(100000); +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return run(argv[1]); + +} + diff --git a/frida_mode/test/exe/GNUmakefile b/frida_mode/test/exe/GNUmakefile new file mode 100644 index 00000000..c543cca8 --- /dev/null +++ b/frida_mode/test/exe/GNUmakefile @@ -0,0 +1,50 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< -no-pie + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ \ No newline at end of file diff --git a/frida_mode/test/exe/Makefile b/frida_mode/test/exe/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/exe/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/exe/testinstr.c b/frida_mode/test/exe/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/exe/testinstr.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile new file mode 100644 index 00000000..515728c4 --- /dev/null +++ b/frida_mode/test/png/GNUmakefile @@ -0,0 +1,109 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +LIBPNG_BUILD_DIR:=$(BUILD_DIR)libpng/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PNGTEST_BUILD_DIR:=$(BUILD_DIR)pngtest/ + +LIBPNG_FILE:=$(LIBPNG_BUILD_DIR)libpng-1.2.56.tar.gz +LIBPNG_URL:=https://downloads.sourceforge.net/project/libpng/libpng12/older-releases/1.2.56/libpng-1.2.56.tar.gz +LIBPNG_DIR:=$(LIBPNG_BUILD_DIR)libpng-1.2.56/ +LIBPNG_MAKEFILE:=$(LIBPNG_DIR)Makefile +LIBPNG_LIB:=$(LIBPNG_DIR).libs/libpng12.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PNGTEST_FILE:=$(PNGTEST_BUILD_DIR)target.cc +PNGTEST_OBJ:=$(PNGTEST_BUILD_DIR)target.o +PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpng-1.2.56/target.cc" + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(LIBPNG_DIR)contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) -o $@ -c $< + +######### PNGTEST ######## + +$(PNGTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR) + wget -O $@ $(PNGTEST_URL) + +$(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) + $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + +######### LIBPNG ######## + +$(LIBPNG_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPNG_FILE): | $(LIBPNG_BUILD_DIR) + wget -O $@ $(LIBPNG_URL) + +$(LIBPNG_DIR): $(LIBPNG_FILE) + tar zxvf $(LIBPNG_FILE) -C $(LIBPNG_BUILD_DIR) + +$(LIBPNG_MAKEFILE): | $(LIBPNG_DIR) + cd $(LIBPNG_DIR) && ./configure + +$(LIBPNG_LIB): $(LIBPNG_MAKEFILE) + make -C $(LIBPNG_DIR) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) + $(CXX) \ + -o $@ \ + $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ + -lz \ + $(TEST_BIN_LDFLAGS) \ + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: $(TEST_BIN) + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ diff --git a/frida_mode/test/png/Makefile b/frida_mode/test/png/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/png/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile new file mode 100644 index 00000000..531f9bce --- /dev/null +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -0,0 +1,79 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_BIN:=$(PWD)../build/test +TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000) +endif + +.PHONY: all clean qemu qemu_entry frida frida_entry + +all: + make -C $(ROOT)frida_mode/test/png/ + +$(BUILD_DIR): + mkdir -p $@ + +qemu: | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +qemu_entry: | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida: | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +frida_entry: | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) @@ + +clean: + rm -rf $(BUILD_DIR) \ No newline at end of file diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile new file mode 100644 index 00000000..5fde63c2 --- /dev/null +++ b/frida_mode/test/png/persistent/Makefile @@ -0,0 +1,18 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +qemu_entry: + @gmake qemu_entry + +frida: + @gmake frida + +frida_entry: + @gmake frida_entry \ No newline at end of file diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py new file mode 100755 index 00000000..6458c212 --- /dev/null +++ b/frida_mode/test/png/persistent/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) \ No newline at end of file diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile new file mode 100644 index 00000000..4f55fe98 --- /dev/null +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -0,0 +1,98 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_DIR=$(ROOT)utils/aflpp_driver/ +AFLPP_DRIVER_HOOK_OBJ=$(AFLPP_DRIVER_HOOK_DIR)aflpp_qemu_driver_hook.so + +TEST_BIN:=$(PWD)../../build/test +TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/ + +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +.PHONY: all clean qemu qemu_entry frida frida_entry + +all: + make -C $(ROOT)frida_mode/test/png/persistent/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + truncate -s 1M $@ + +$(AFLPP_DRIVER_HOOK_OBJ): | $(AFLPP_DRIVER_HOOK_DIR) + make -C $(AFLPP_DRIVER_HOOK_DIR) + +qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)/afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +qemu_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)/afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + + +frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +clean: + rm -rf $(BUILD_DIR) + diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile new file mode 100644 index 00000000..5fde63c2 --- /dev/null +++ b/frida_mode/test/png/persistent/hook/Makefile @@ -0,0 +1,18 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +qemu_entry: + @gmake qemu_entry + +frida: + @gmake frida + +frida_entry: + @gmake frida_entry \ No newline at end of file diff --git a/frida_mode/test/testinstr.c b/frida_mode/test/testinstr.c deleted file mode 100644 index 37d47f91..00000000 --- a/frida_mode/test/testinstr.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - american fuzzy lop++ - a trivial program to test the build - -------------------------------------------------------- - Originally written by Michal Zalewski - Copyright 2014 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - */ - -#include -#include -#include -#include -#include - -#ifdef __APPLE__ - #define TESTINSTR_SECTION -#else - #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) -#endif - -TESTINSTR_SECTION void testinstr(char *buf, int len) { - - if (len < 1) return; - buf[len] = 0; - - // we support three input cases - if (buf[0] == '0') - printf("Looks like a zero to me!\n"); - else if (buf[0] == '1') - printf("Pretty sure that is a one!\n"); - else - printf("Neither one or zero? How quaint!\n"); - -} - -int main(int argc, char **argv) { - - char * file; - int fd = -1; - off_t len; - char * buf = NULL; - size_t n_read; - int result = -1; - - if (argc != 2) { return 1; } - - do { - - file = argv[1]; - - dprintf(STDERR_FILENO, "Running: %s\n", file); - - fd = open(file, O_RDONLY); - if (fd < 0) { - - perror("open"); - break; - - } - - len = lseek(fd, 0, SEEK_END); - if (len < 0) { - - perror("lseek (SEEK_END)"); - break; - - } - - if (lseek(fd, 0, SEEK_SET) != 0) { - - perror("lseek (SEEK_SET)"); - break; - - } - - buf = malloc(len); - if (buf == NULL) { - - perror("malloc"); - break; - - } - - n_read = read(fd, buf, len); - if (n_read != len) { - - perror("read"); - break; - - } - - dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); - - testinstr(buf, len); - dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); - - result = 0; - - } while (false); - - if (buf != NULL) { free(buf); } - - if (fd != -1) { close(fd); } - - return result; - -} - diff --git a/frida_mode/test/testinstr.py b/frida_mode/test/testinstr.py deleted file mode 100755 index f648808b..00000000 --- a/frida_mode/test/testinstr.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 -import argparse -from elftools.elf.elffile import ELFFile - - -def process_file(file, section, base): - with open(file, "rb") as f: - for sect in ELFFile(f).iter_sections(): - if sect.name == section: - start = base + sect.header["sh_offset"] - end = start + sect.header["sh_size"] - print("0x%016x-0x%016x" % (start, end)) - return - - print("Section '%s' not found in '%s'" % (section, file)) - - -def hex_value(x): - return int(x, 16) - - -def main(): - parser = argparse.ArgumentParser(description="Process some integers.") - parser.add_argument( - "-f", "--file", dest="file", type=str, help="elf file name", required=True - ) - parser.add_argument( - "-s", - "--section", - dest="section", - type=str, - help="elf section name", - required=True, - ) - parser.add_argument( - "-b", - "--base", - dest="base", - type=hex_value, - help="elf base address", - required=True, - ) - - args = parser.parse_args() - process_file(args.file, args.section, args.base) - - -if __name__ == "__main__": - main() diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile new file mode 100644 index 00000000..4addbad8 --- /dev/null +++ b/frida_mode/test/testinstr/GNUmakefile @@ -0,0 +1,50 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ \ No newline at end of file diff --git a/frida_mode/test/testinstr/Makefile b/frida_mode/test/testinstr/Makefile new file mode 100644 index 00000000..f322d1f5 --- /dev/null +++ b/frida_mode/test/testinstr/Makefile @@ -0,0 +1,12 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida \ No newline at end of file diff --git a/frida_mode/test/testinstr/testinstr.c b/frida_mode/test/testinstr/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/testinstr/testinstr.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/update_frida_version.sh b/frida_mode/update_frida_version.sh new file mode 100755 index 00000000..7d938712 --- /dev/null +++ b/frida_mode/update_frida_version.sh @@ -0,0 +1,13 @@ +#!/bin/sh +test -n "$1" && { echo This script has no options. It updates the referenced Frida version in GNUmakefile to the most current one. ; exit 1 ; } + +OLD=$(egrep '^GUM_DEVKIT_VERSION=' GNUmakefile 2>/dev/null|awk -F= '{print$2}') +NEW=$(curl https://github.com/frida/frida/releases/ 2>/dev/null|egrep 'frida-gum-devkit-[0-9.]*-linux-x86_64'|head -n 1|sed 's/.*frida-gum-devkit-//'|sed 's/-linux.*//') + +echo Current set version: $OLD +echo Newest available version: $NEW + +test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; } + +sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1 +echo Successfully updated GNUmakefile diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index f201782a..72f956b9 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -392,7 +392,7 @@ typedef struct afl_env_vars { *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, - *afl_persistent_record; + *afl_persistent_record, *afl_exit_on_time; } afl_env_vars_t; @@ -575,7 +575,8 @@ typedef struct afl_state { last_sync_cycle, /* Cycle no. of the last sync */ last_path_time, /* Time for most recent path (ms) */ last_crash_time, /* Time for most recent crash (ms) */ - last_hang_time; /* Time for most recent hang (ms) */ + last_hang_time, /* Time for most recent hang (ms) */ + exit_on_time; /* Delay to exit if no new paths */ u32 slowest_exec_ms, /* Slowest testcase non hang in ms */ subseq_tmouts; /* Number of timeouts in a row */ @@ -1134,6 +1135,7 @@ void check_if_tty(afl_state_t *); void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); void read_foreign_testcases(afl_state_t *, int); +void write_crash_readme(afl_state_t *afl); /* CmpLog */ diff --git a/include/envs.h b/include/envs.h index ebe98257..9175005e 100644 --- a/include/envs.h +++ b/include/envs.h @@ -49,6 +49,7 @@ static char *afl_environment_variables[] = { "AFL_DUMB_FORKSRV", "AFL_ENTRYPOINT", "AFL_EXIT_WHEN_DONE", + "AFL_EXIT_ON_TIME", "AFL_EXIT_ON_SEED_ISSUES", "AFL_FAST_CAL", "AFL_FORCE_UI", @@ -59,6 +60,9 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_STRICT", "AFL_FRIDA_INST_TRACE", + "AFL_FRIDA_PERSISTENT_ADDR", + "AFL_FRIDA_PERSISTENT_CNT", + "AFL_FRIDA_PERSISTENT_HOOK", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 0937a328..cfe537d5 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -2,7 +2,7 @@ (See [../README.md](../README.md) for the general instruction manual.) - (See [README.gcc_plugon.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) + (See [README.gcc_plugin.md](../README.gcc_plugin.md) for the GCC-based instrumentation.) ## 1) Introduction diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 6dd390e6..2f4337eb 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -60,15 +60,14 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -// static const char *const SanCovTracePCGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +// const char SanCovTracePCGuardName = // "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; static cl::opt ClCoverageLevel( "lto-coverage-level", diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 09cda9e2..8878d3b1 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -52,49 +52,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; -static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; -static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; -static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; -static const char *const SanCovTraceConstCmp1 = - "__sanitizer_cov_trace_const_cmp1"; -static const char *const SanCovTraceConstCmp2 = - "__sanitizer_cov_trace_const_cmp2"; -static const char *const SanCovTraceConstCmp4 = - "__sanitizer_cov_trace_const_cmp4"; -static const char *const SanCovTraceConstCmp8 = - "__sanitizer_cov_trace_const_cmp8"; -static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; -static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; -static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; -static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; -static const char *const SanCovModuleCtorTracePcGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -static const char *const SanCovModuleCtor8bitCountersName = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -static const char *const SanCovModuleCtorBoolFlagName = - "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -static const char *const SanCovTracePCGuardName = - "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovTracePCGuardInitName = - "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName = - "__sanitizer_cov_8bit_counters_init"; -static const char *const SanCovBoolFlagInitName = - "__sanitizer_cov_bool_flag_init"; -static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static char *skip_nozero; @@ -320,12 +310,12 @@ std::pair ModuleSanitizerCoverage::CreateSecStartEnd( Module &M, const char *Section, Type *Ty) { GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionStart(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) @@ -573,7 +563,7 @@ bool ModuleSanitizerCoverage::instrumentModule( } // True if block has successors and it dominates all of them. -static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { +bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { if (succ_begin(BB) == succ_end(BB)) return false; @@ -588,8 +578,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { } // True if block has predecessors and it postdominates all of them. -static bool isFullPostDominator(const BasicBlock * BB, - const PostDominatorTree *PDT) { +bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { if (pred_begin(BB) == pred_end(BB)) return false; @@ -603,10 +592,10 @@ static bool isFullPostDominator(const BasicBlock * BB, } -static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, - const SanitizerCoverageOptions &Options) { +bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, + const DominatorTree * DT, + const PostDominatorTree * PDT, + const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we // will never call __sanitizer_cov() for them, so counting them in @@ -636,8 +625,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // A twist here is that we treat From->To as a backedge if // * To dominates From or // * To->UniqueSuccessor dominates From -static bool IsBackEdge(BasicBlock *From, BasicBlock *To, - const DominatorTree *DT) { +bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { if (DT->dominates(To, From)) return true; if (auto Next = To->getUniqueSuccessor()) @@ -651,8 +639,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To, // // Note that Cmp pruning is controlled by the same flag as the // BB pruning. -static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, - const SanitizerCoverageOptions &Options) { +bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, + const SanitizerCoverageOptions &Options) { if (!Options.NoPrune) if (CMP->hasOneUse()) @@ -1046,7 +1034,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (IsEntryBB) { - // Keep static allocas and llvm.localescape calls in the entry block. Even + // Keep allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); @@ -1221,17 +1209,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( } -static void registerPCGUARDPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { +void registerPCGUARDPass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { auto p = new ModuleSanitizerCoverageLegacyPass(); PM.add(p); } -static RegisterStandardPasses RegisterCompTransPass( +RegisterStandardPasses RegisterCompTransPass( PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass); -static RegisterStandardPasses RegisterCompTransPass0( +RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 552bbea8..2089ce78 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -79,8 +79,9 @@ #endif #if defined(__HAIKU__) - extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); -#endif // HAIKU +extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, + size_t bufferSize); +#endif // HAIKU u8 __afl_area_initial[MAP_INITIAL_SIZE]; u8 * __afl_area_ptr_dummy = __afl_area_initial; @@ -1754,11 +1755,11 @@ static int area_is_valid(void *ptr, size_t len) { if (unlikely(!ptr || __asan_region_is_poisoned(ptr, len))) { return 0; } - #ifndef __HAIKU__ - long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); - #else - long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); - #endif // HAIKU +#ifndef __HAIKU__ + long r = syscall(SYS_write, __afl_dummy_fd[1], ptr, len); +#else + long r = _kern_write(__afl_dummy_fd[1], -1, ptr, len); +#endif // HAIKU if (r <= 0 || r > len) return 0; diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index 41bb5152..3b7eb878 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -177,7 +177,7 @@ int plugin_is_GPL_compatible = 1; namespace { -static const struct pass_data afl_pass_data = { +static constexpr struct pass_data afl_pass_data = { .type = GIMPLE_PASS, .name = "afl", @@ -503,7 +503,7 @@ struct afl_pass : gimple_opt_pass { // Starting from "LLVMFuzzer" these are functions used in libfuzzer based // fuzzing campaign installations, e.g. oss-fuzz - static const char *ignoreList[] = { + static constexpr const char *ignoreList[] = { "asan.", "llvm.", diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 24498f3e..af32e2f9 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -55,7 +55,7 @@ bool isIgnoreFunction(const llvm::Function *F) { // Starting from "LLVMFuzzer" these are functions used in libfuzzer based // fuzzing campaign installations, e.g. oss-fuzz - static const char *ignoreList[] = { + static constexpr const char *ignoreList[] = { "asan.", "llvm.", @@ -94,7 +94,7 @@ bool isIgnoreFunction(const llvm::Function *F) { } - static const char *ignoreSubstringList[] = { + static constexpr const char *ignoreSubstringList[] = { "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize", "__cxx", "_GLOBAL__", diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index f6cdbe9e..68bd2fa5 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -89,11 +89,11 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t afl_global_id = 1, autodictionary = 1; - uint32_t function_minimum_size = 1; - uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; + uint32_t afl_global_id = 1, autodictionary = 1; + uint32_t function_minimum_size = 1; + uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - char * skip_nozero = NULL; + char * skip_nozero = NULL; }; diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index 97ab04a4..82f198aa 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -89,7 +89,7 @@ class SplitSwitchesTransform : public ModulePass { }; - typedef std::vector CaseVector; + using CaseVector = std::vector; private: bool splitSwitches(Module &M); diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 4aa2133e..38cb5ba6 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -190,8 +190,8 @@ handlers of the target. ## 13) Gotchas, feedback, bugs -If you need to fix up checksums or do other cleanup on mutated test cases, see -utils/custom_mutators/ for a viable solution. +If you need to fix up checksums or do other cleanups on mutated test cases, see +`afl_custom_post_process` in custom_mutators/examples/example.c for a viable solution. Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate the "shadow VM" trick employed by the sanitizers and will probably just diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 02a44cef..84f144be 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -9,7 +9,7 @@ # TCG instrumentation and block chaining support by Andrea Biondo # # -# QEMU 3.1.1 port, TCG thread-safety, CompareCoverage and NeverZero +# QEMU 5+ port, TCG thread-safety, CompareCoverage and NeverZero # counters by Andrea Fioraldi # # Copyright 2015, 2016, 2017 Google Inc. All rights reserved. diff --git a/src/afl-cc.c b/src/afl-cc.c index 1f89bac5..09009334 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -560,12 +560,14 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode && !have_c) { u8 *ld_path = strdup(AFL_REAL_LD); - if (!*ld_path) ld_path = "ld.lld"; + if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); } + if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); } #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12 cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path); #else cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path); #endif + free(ld_path); cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 727e7f8d..a07e78b4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -416,7 +416,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false) { + if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && + fsrv->frida_mode == false) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv @@ -1089,7 +1090,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { #endif - if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { + if (likely(fsrv->use_shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 3d0228db..97f10e6f 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -397,7 +397,7 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) { /* Write a message accompanying the crash directory :-) */ -static void write_crash_readme(afl_state_t *afl) { +void write_crash_readme(afl_state_t *afl) { u8 fn[PATH_MAX]; s32 fd; diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 27c6c413..c2e9c80f 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -35,7 +35,7 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); } - if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { + if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) { argv[0] = fsrv->cmplog_binary; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b6bfbc29..cb586111 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2031,7 +2031,7 @@ void setup_dirs_fds(afl_state_t *afl) { fprintf( afl->fsrv.plot_file, - "# unix_time, cycles_done, cur_path, paths_total, " + "# relative_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " "unique_hangs, max_depth, execs_per_sec, total_execs, edges_found\n"); @@ -2774,6 +2774,14 @@ void check_binary(afl_state_t *afl, u8 *fname) { WARNF("AFL_PERSISTENT is no longer supported and may misbehave!"); + } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) { + + OKF("FRIDA Persistent mode configuration options detected."); + setenv(PERSIST_ENV_VAR, "1", 1); + afl->persistent_mode = 1; + + afl->shmem_testcase_mode = 1; + } if (afl->fsrv.frida_mode || diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index c99d9a4d..e27d6fae 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -308,9 +308,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, struct custom_mutator *mutator) { - u8 needs_write = 0, fault = 0; + u8 fault = 0; u32 trim_exec = 0; u32 orig_len = q->len; + u32 out_len = 0; + u8 *out_buf = NULL; u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -397,33 +399,33 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen && cksum == q->exec_cksum)) { - if (afl_realloc((void **)&in_buf, retlen) == NULL) { - - FATAL("can not allocate memory for trim"); - - } - - memcpy(in_buf, retbuf, retlen); - q->len = retlen; - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + update_bitmap_score once we're done with the trimming stuff. + Use out_buf NULL check to make this only happen once per trim. */ - if (!needs_write) { + if (!out_buf) { - needs_write = 1; memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, afl->fsrv.map_size); } + if (afl_realloc((void **)&out_buf, retlen) == NULL) { + + FATAL("can not allocate memory for trim"); + + } + + out_len = retlen; + memcpy(out_buf, retbuf, retlen); + /* Tell the custom mutator that the trimming was successful */ afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 1); if (afl->not_on_tty && afl->debug) { SAYF("[Custom Trimming] SUCCESS: %u/%u iterations (now at %u bytes)", - afl->stage_cur, afl->stage_max, q->len); + afl->stage_cur, afl->stage_max, out_len); } @@ -456,16 +458,10 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } - if (afl->not_on_tty && afl->debug) { - - SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); - - } - - /* If we have made changes to in_buf, we also need to update the on-disk + /* If we have made changes, we also need to update the on-disk version of the test case. */ - if (needs_write) { + if (out_buf) { s32 fd; @@ -475,16 +471,28 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } - ck_write(fd, in_buf, q->len, q->fname); + ck_write(fd, out_buf, out_len, q->fname); close(fd); + /* Update the queue's knowledge of length as soon as we write the file. + We do this here so that exit/error cases that *don't* update the file + also don't update q->len. */ + q->len = out_len; + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } + if (afl->not_on_tty && afl->debug) { + + SAYF("[Custom Trimming] DONE: %u bytes -> %u bytes", orig_len, q->len); + + } + abort_trimming: + if (out_buf) afl_free(out_buf); afl->bytes_trim_out += q->len; return fault; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index d72d4145..4eeb93de 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -3010,13 +3010,13 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u8 res = trim_case(afl, afl->queue_cur, in_buf); orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); - if (res == FSRV_RUN_ERROR) { + if (unlikely(res == FSRV_RUN_ERROR)) { FATAL("Unable to execute target application"); } - if (afl->stop_soon) { + if (unlikely(afl->stop_soon)) { ++afl->cur_skipped_paths; goto abandon_entry; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 832f17bb..6e5210b8 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (afl->fsrv.shmem_fuzz) { + if (likely(afl->fsrv.use_shmem_fuzz)) { if (!post_process_skipped) { @@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); - } - - else { + } else { memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); @@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, return; - } else if (afl->fsrv.out_file) { + } else if (unlikely(!afl->fsrv.use_stdin)) { if (unlikely(afl->no_unlink)) { @@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (!afl->fsrv.out_file) { + if (afl->fsrv.use_stdin) { if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 28d3339a..c886cb28 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; + afl->exit_on_time = 0; afl->stats_update_freq = 1; afl->stats_avg_exec = 0; afl->skip_deterministic = 1; @@ -187,6 +188,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_exit_when_done = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_EXIT_ON_TIME", + + afl_environment_variable_len)) { + + afl->afl_env.afl_exit_on_time = + (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_NO_AFFINITY", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 22c0cbd2..313263f9 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -179,6 +179,8 @@ void load_stats_file(afl_state_t *afl) { } + if (afl->unique_crashes) { write_crash_readme(afl); } + return; } @@ -384,7 +386,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, /* Fields in the file: - unix_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, + relative_time, afl->cycles_done, cur_path, paths_total, paths_not_fuzzed, favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, execs_per_sec, edges_found */ @@ -544,7 +546,7 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_statsd)) { - if (unlikely(afl->force_ui_update && cur_ms - afl->statsd_last_send_ms > + if (unlikely(afl->force_ui_update || cur_ms - afl->statsd_last_send_ms > STATSD_UPDATE_SEC * 1000)) { /* reset counter, even if send failed. */ @@ -574,6 +576,16 @@ void show_stats(afl_state_t *afl) { } + /* AFL_EXIT_ON_TIME. */ + + if (unlikely(afl->last_path_time && !afl->non_instrumented_mode && + afl->afl_env.afl_exit_on_time && + (cur_ms - afl->last_path_time) > afl->exit_on_time)) { + + afl->stop_soon = 2; + + } + if (unlikely(afl->total_crashes && afl->afl_env.afl_bench_until_crash)) { afl->stop_soon = 2; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3606533d..8de3ed6b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -204,6 +204,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" + "AFL_EXIT_ON_TIME: exit when no new paths are found within the specified time period\n" "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60 minutes and a cycle without finds)\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" @@ -1246,6 +1247,13 @@ int main(int argc, char **argv_orig, char **envp) { } + if (afl->afl_env.afl_exit_on_time) { + + u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time); + afl->exit_on_time = (u64)exit_on_time * 1000; + + } + if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); @@ -1358,6 +1366,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_preload = getenv("AFL_PRELOAD"); u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); if (afl_preload) { frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); @@ -1383,6 +1392,7 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); setenv("LD_PRELOAD", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); ck_free(frida_binary); @@ -1697,13 +1707,14 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: this is semi-nice afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; + afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode; afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; afl->cmplog_fsrv.init_child_func = cmplog_exec_child; if ((map_size <= DEFAULT_SHMEM_SIZE || afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->fsrv.frida_mode && !afl->unicorn_mode) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; @@ -2209,6 +2220,31 @@ stop_fuzzing: } afl_fsrv_deinit(&afl->fsrv); + + /* remove tmpfile */ + if (afl->tmp_dir != NULL && !afl->in_place_resume) { + + char tmpfile[PATH_MAX]; + + if (afl->file_extension) { + + snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, + afl->file_extension); + + } else { + + snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir); + + } + + if (unlink(tmpfile) != 0) { + + FATAL("Could not unlink current input file: %s.", tmpfile); + + } + + } + if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index d0113af9..1ce97649 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -298,13 +298,12 @@ int main(int argc, char **argv) { SAYF( "\n" - "This is a helper application for afl-clang-lto. It is a wrapper " - "around GNU " - "llvm's 'lld',\n" - "executed by the toolchain whenever using " - "afl-clang-lto/afl-clang-lto++.\n" + "This is a helper application for afl-clang-lto.\n" + "It is a wrapper around llvm's 'lld' in case afl-clang-lto cannot be " + "used.\n" + "Note that the target still has to be compiled with -flto=full!\n" "You probably don't want to run this program directly but rather pass " - "it as LD parameter to configure scripts\n\n" + "it as LD\nparameter to e.g. configure scripts.\n\n" "Environment variables:\n" " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n" diff --git a/test/test-all.sh b/test/test-all.sh index 8df4bef9..0c189727 100755 --- a/test/test-all.sh +++ b/test/test-all.sh @@ -14,6 +14,8 @@ . ./test-qemu-mode.sh +. ./test-frida-mode.sh + . ./test-unicorn-mode.sh . ./test-custom-mutators.sh diff --git a/test/test-custom-mutators.sh b/test/test-custom-mutators.sh index bae4220f..5d679a82 100755 --- a/test/test-custom-mutators.sh +++ b/test/test-custom-mutators.sh @@ -5,7 +5,7 @@ $ECHO "$BLUE[*] Testing: custom mutator" test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { # normalize path - CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../utils/custom_mutators;pwd) + CUSTOM_MUTATOR_PATH=$(cd $(pwd)/../custom_mutators/examples;pwd) test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { unset AFL_CC # Compile the vulnerable program for single mutator @@ -29,8 +29,8 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { } } # Compile the custom mutator - cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 - cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../utils/custom_mutators/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x41 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator.so > /dev/null 2>&1 + cc -D_FIXED_CHAR=0x42 -g -fPIC -shared -I../include ../custom_mutators/examples/simple_example.c -o libexamplemutator2.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ./libexamplemutator.so && { # Create input directory mkdir -p in diff --git a/test/test-frida-mode.sh b/test/test-frida-mode.sh new file mode 100755 index 00000000..b47d016a --- /dev/null +++ b/test/test-frida-mode.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +. ./test-pre.sh + +$ECHO "$BLUE[*] Testing: frida_mode" +test -z "$AFL_CC" && { + if type gcc >/dev/null; then + export AFL_CC=gcc + else + if type clang >/dev/null; then + export AFL_CC=clang + fi + fi +} + +test -e ../afl-frida-trace.so && { + cc -no-pie -o test-instr ../test-instr.c + cc -o test-compcov test-compcov.c + test -e test-instr -a -e test-compcov && { + { + mkdir -p in + echo 00000 > in/in + $ECHO "$GREY[*] running afl-fuzz for frida_mode, this will take approx 10 seconds" + { + ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr >>errors 2>&1 + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode" + RUNTIME=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'` + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode" + CODE=1 + } + rm -f errors + + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + $ECHO "$GREY[*] running afl-fuzz for frida_mode cmplog, this will take approx 10 seconds" + { + ../afl-fuzz -m none -V10 -O -c 0 -i in -o out -- ./test-compcov >>errors 2>&1 + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000003* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with frida_mode cmplog" + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with frida_mode cmplog" + CODE=1 + } + rm -f errors + } || { + $ECHO "$YELLOW[-] not an intel or arm platform, cannot test frida_mode cmplog" + } + + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && { + $ECHO "$GREY[*] running afl-fuzz for persistent frida_mode, this will take approx 10 seconds" + { + #if file test-instr | grep -q "32-bit"; then + #else + #fi + export AFL_FRIDA_PERSISTENT_ADDR=0x`nm test-instr | grep "T main" | awk '{print $1}'` + $ECHO "Info: AFL_FRIDA_PERSISTENT_ADDR=$AFL_FRIDA_PERSISTENT_ADDR <= $(nm test-instr | grep "T main" | awk '{print $1}')" + env|grep AFL_|sort + file test-instr + ../afl-fuzz -m ${MEM_LIMIT} -V10 -O -i in -o out -- ./test-instr + unset AFL_FRIDA_PERSISTENT_ADDR + } >>errors 2>&1 + test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && { + $ECHO "$GREEN[+] afl-fuzz is working correctly with persistent frida_mode" + RUNTIMEP=`grep execs_done out/default/fuzzer_stats | awk '{print$3}'` + test -n "$RUNTIME" -a -n "$RUNTIMEP" && { + DIFF=`expr $RUNTIMEP / $RUNTIME` + test "$DIFF" -gt 1 && { # must be at least twice as fast + $ECHO "$GREEN[+] persistent frida_mode was noticeable faster than standard frida_mode" + } || { + $ECHO "$YELLOW[-] persistent frida_mode was not noticeable faster than standard frida_mode" + } + } || { + $ECHO "$YELLOW[-] we got no data on executions performed? weird!" + } + } || { + echo CUT------------------------------------------------------------------CUT + cat errors + echo CUT------------------------------------------------------------------CUT + $ECHO "$RED[!] afl-fuzz is not working correctly with persistent frida_mode" + CODE=1 + } + rm -rf in out errors + } || { + $ECHO "$YELLOW[-] not an intel or arm platform, cannot test persistent frida_mode" + } + + } + } || { + $ECHO "$RED[!] gcc compilation of test targets failed - what is going on??" + CODE=1 + } + + rm -f test-instr test-compcov +} || { + $ECHO "$YELLOW[-] frida_mode is not compiled, cannot test" + INCOMPLETE=1 +} + +. ./test-post.sh diff --git a/test/test-performance.sh b/test/test-performance.sh index cd9f6caf..d61e2f2a 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -18,6 +18,7 @@ export AFL_QUIET=1 export AFL_PATH=`pwd`/.. unset AFL_EXIT_WHEN_DONE +unset AFL_EXIT_ON_TIME unset AFL_SKIP_CPUFREQ unset AFL_DEBUG unset AFL_HARDEN diff --git a/test/test-pre.sh b/test/test-pre.sh index 174f2f7f..7819da47 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -62,6 +62,7 @@ $ECHO \\101 2>&1 | grep -qE '^A' || { test -z "$ECHO" && { printf Error: printf command does not support octal character codes ; exit 1 ; } export AFL_EXIT_WHEN_DONE=1 +export AFL_EXIT_ON_TIME=60 export AFL_SKIP_CPUFREQ=1 export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 unset AFL_NO_X86 diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index d9ae5590..ffcf3b4c 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -fb2fc9f2 +019b871539fe9ed3f41d882385a8b02c243d49ad diff --git a/unicorn_mode/samples/speedtest/c/Makefile b/unicorn_mode/samples/speedtest/c/Makefile index ce784d4f..46789954 100644 --- a/unicorn_mode/samples/speedtest/c/Makefile +++ b/unicorn_mode/samples/speedtest/c/Makefile @@ -29,7 +29,11 @@ MYCC = $(__CC:$(_UNIQ)$(CROSS)=$(CROSS)gcc) .PHONY: all clean -all: fuzz +all: ../target harness + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz clean: rm -rf *.o harness harness-debug @@ -49,6 +53,6 @@ harness-debug: harness-debug.o ../target: $(MAKE) -C .. -fuzz: ../target harness +fuzz: all afl-fuzz rm -rf ./output - SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@ + SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./harness @@ diff --git a/unicorn_mode/samples/speedtest/python/Makefile b/unicorn_mode/samples/speedtest/python/Makefile index 4282c6cb..c0c64269 100644 --- a/unicorn_mode/samples/speedtest/python/Makefile +++ b/unicorn_mode/samples/speedtest/python/Makefile @@ -1,8 +1,15 @@ -all: fuzz +.PHONY: all fuzz + +all: ../target + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz + ../target: $(MAKE) -C .. -fuzz: ../target +fuzz: all afl-fuzz rm -rf ./ouptput ../../../../afl-fuzz -s 1 -U -i ../sample_inputs -o ./output -- python3 harness.py @@ diff --git a/unicorn_mode/samples/speedtest/rust/Makefile b/unicorn_mode/samples/speedtest/rust/Makefile index fe18d6ee..46934c93 100644 --- a/unicorn_mode/samples/speedtest/rust/Makefile +++ b/unicorn_mode/samples/speedtest/rust/Makefile @@ -1,4 +1,10 @@ -all: fuzz +.PHONY: all fuzz + +all: ../target ./target/release/unicornafl_harness + +afl-fuzz: ../../../../afl-fuzz +../../../../afl-fuzz: + $(MAKE) -C ../../../../ afl-fuzz clean: cargo clean @@ -12,6 +18,6 @@ clean: ../target: $(MAKE) -c .. -fuzz: ../target ./target/release/unicornafl_harness +fuzz: all afl-fuzz rm -rf ./output - SKIP_BINCHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@ + SKIP_BIN_CHECK=1 ../../../../afl-fuzz -s 1 -i ../sample_inputs -o ./output -- ./target/release/unicornafl_harness @@ diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index fb2fc9f2..019b8715 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit fb2fc9f25df32f17f6b6b859e4dbd70f9a857e0c +Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad diff --git a/utils/README.md b/utils/README.md index 336b6b6c..b157424f 100644 --- a/utils/README.md +++ b/utils/README.md @@ -32,7 +32,8 @@ Here's a quick overview of the stuff you can find in this directory: with additional gdb metadata. - custom_mutators - examples for the afl++ custom mutator interface in - C and Python + C and Python. Note: They were moved to + ../custom_mutators/examples/ - distributed_fuzzing - a sample script for synchronizing fuzzer instances across multiple machines (see parallel_fuzzing.md). diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index aa7a361a..6006e238 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -70,6 +70,10 @@ static void __afl_map_shm(void) { char *id_str = getenv(SHM_ENV_VAR); char *ptr; + /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then + uncomment the following: */ + + /* if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { u32 val = atoi(ptr); @@ -77,6 +81,8 @@ static void __afl_map_shm(void) { } + */ + if (__afl_map_size > MAP_SIZE) { if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { @@ -189,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* report that we are starting the target */ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - if (status < 1) - return 0; - else - return status; + return status; } @@ -210,7 +213,7 @@ int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; + s32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. Any value is fine as long as it can be divided by 32. */ @@ -222,10 +225,20 @@ int main(int argc, char *argv[]) { while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ + if (len > 4) { // the minimum data size you need for the target + + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ - // ... the magic ... + // ... the magic ... + + // remove this, this is just to make afl-fuzz not complain when run + if (buf[0] == 0xff) + __afl_area_ptr[1] = 1; + else + __afl_area_ptr[2] = 2; + + } /* report the test case is done and wait for the next */ __afl_end_testcase(); diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index 8ac054a6..ad99b893 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -7,7 +7,7 @@ ifneq "" "$(LLVM_BINDIR)" LLVM_BINDIR := $(LLVM_BINDIR)/ endif -CFLAGS := -O3 -funroll-loops -g +CFLAGS := -O3 -funroll-loops -g -fPIC all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so @@ -33,10 +33,10 @@ libAFLQemuDriver.a: aflpp_qemu_driver.o -cp -vf libAFLQemuDriver.a ../../ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - -$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so + -test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + -test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c index d3dd98b0..2979fadc 100644 --- a/utils/aflpp_driver/aflpp_qemu_driver_hook.c +++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c @@ -3,12 +3,12 @@ #include #include -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -16,11 +16,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use diff --git a/utils/custom_mutators/Makefile b/utils/custom_mutators/Makefile deleted file mode 100644 index 9849f3f4..00000000 --- a/utils/custom_mutators/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: libexamplemutator.so - -libexamplemutator.so: - $(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so - -clean: - rm -rf libexamplemutator.so diff --git a/utils/custom_mutators/README.md b/utils/custom_mutators/README.md deleted file mode 100644 index 655f7a5e..00000000 --- a/utils/custom_mutators/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Examples for the custom mutator - -These are example and helper files for the custom mutator feature. -See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information - -Note that if you compile with python3.7 you must use python3 scripts, and if -you use python2.7 to compile python2 scripts! - -simple_example.c - most simplest example. generates a random sized buffer - filled with 'A' - -example.c - this is a simple example written in C and should be compiled to a - shared library. Use make to compile it and produce libexamplemutator.so - -example.py - this is the template you can use, the functions are there but they - are empty - -post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF - -post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG - -simple-chunk-replace.py - this is a simple example where chunks are replaced - -common.py - this can be used for common functions and helpers. - the examples do not use this though. But you can :) - -wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py - -XmlMutatorMin.py - module for XML mutation - -custom_mutator_helpers.h is an header that defines some helper routines -like surgical_havoc_mutate() that allow to perform a randomly chosen -mutation from a subset of the havoc mutations. -If you do so, you have to specify -I /path/to/AFLplusplus/include when -compiling. diff --git a/utils/custom_mutators/XmlMutatorMin.py b/utils/custom_mutators/XmlMutatorMin.py deleted file mode 100644 index 3e6cd0ff..00000000 --- a/utils/custom_mutators/XmlMutatorMin.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/python - -""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """ - -from __future__ import print_function -from copy import deepcopy -from lxml import etree as ET -import random, re, io - - -########################### -# The XmlMutatorMin class # -########################### - - -class XmlMutatorMin: - - """ - Optionals parameters: - seed Seed used by the PRNG (default: "RANDOM") - verbose Verbosity (default: False) - """ - - def __init__(self, seed="RANDOM", verbose=False): - - """ Initialize seed, database and mutators """ - - # Verbosity - self.verbose = verbose - - # Initialize PRNG - self.seed = str(seed) - if self.seed == "RANDOM": - random.seed() - else: - if self.verbose: - print("Static seed '%s'" % self.seed) - random.seed(self.seed) - - # Initialize input and output documents - self.input_tree = None - self.tree = None - - # High-level mutators (no database needed) - hl_mutators_delete = [ - "del_node_and_children", - "del_node_but_children", - "del_attribute", - "del_content", - ] # Delete items - hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values - - # Exposed mutators - self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete - - def __parse_xml(self, xml): - - """ Parse an XML string. Basic wrapper around lxml.parse() """ - - try: - # Function parse() takes care of comments / DTD / processing instructions / ... - tree = ET.parse(io.BytesIO(xml)) - except ET.ParseError: - raise RuntimeError("XML isn't well-formed!") - except LookupError as e: - raise RuntimeError(e) - - # Return a document wrapper - return tree - - def __exec_among(self, module, functions, min_times, max_times): - - """ Randomly execute $functions between $min and $max times """ - - for i in xrange(random.randint(min_times, max_times)): - # Function names are mangled because they are "private" - getattr(module, "_XmlMutatorMin__" + random.choice(functions))() - - def __serialize_xml(self, tree): - - """ Serialize a XML document. Basic wrapper around lxml.tostring() """ - - return ET.tostring( - tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding - ) - - def __ver(self, version): - - """ Helper for displaying lxml version numbers """ - - return ".".join(map(str, version)) - - def reset(self): - - """ Reset the mutator """ - - self.tree = deepcopy(self.input_tree) - - def init_from_string(self, input_string): - - """ Initialize the mutator from a XML string """ - - # Get a pointer to the top-element - self.input_tree = self.__parse_xml(input_string) - - # Get a working copy - self.tree = deepcopy(self.input_tree) - - def save_to_string(self): - - """ Return the current XML document as UTF-8 string """ - - # Return a text version of the tree - return self.__serialize_xml(self.tree) - - def __pick_element(self, exclude_root_node=False): - - """ Pick a random element from the current document """ - - # Get a list of all elements, but nodes like PI and comments - elems = list(self.tree.getroot().iter(tag=ET.Element)) - - # Is the root node excluded? - if exclude_root_node: - start = 1 - else: - start = 0 - - # Pick a random element - try: - elem_id = random.randint(start, len(elems) - 1) - elem = elems[elem_id] - except ValueError: - # Should only occurs if "exclude_root_node = True" - return (None, None) - - return (elem_id, elem) - - def __fuzz_attribute(self): - - """ Fuzz (part of) an attribute value """ - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't replace!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # We have the attribute to modify - # Get its value - attrib_value = rand_elem.get(rand_attrib) - # print("- Value: " + attrib_value) - - # Should we work on the whole value? - func_call = "(?P[a-zA-Z:\-]+)\((?P.*?)\)" - p = re.compile(func_call) - l = p.findall(attrib_value) - if random.choice((True, False)) and l: - # Randomly pick one the function calls - (func, args) = random.choice(l) - # Split by "," and randomly pick one of the arguments - value = random.choice(args.split(",")) - # Remove superfluous characters - unclean_value = value - value = value.strip(" ").strip("'") - # print("Selected argument: [%s]" % value) - else: - value = attrib_value - - # For each type, define some possible replacement values - choices_number = ( - "0", - "11111", - "-128", - "2", - "-1", - "1/3", - "42/0", - "1094861636 idiv 1.0", - "-1123329771506872 idiv 3.8", - "17=$numericRTF", - str(3 + random.randrange(0, 100)), - ) - - choices_letter = ( - "P" * (25 * random.randrange(1, 100)), - "%s%s%s%s%s%s", - "foobar", - ) - - choices_alnum = ( - "Abc123", - "020F0302020204030204", - "020F0302020204030204" * (random.randrange(5, 20)), - ) - - # Fuzz the value - if random.choice((True, False)) and value == "": - - # Empty - new_value = value - - elif random.choice((True, False)) and value.isdigit(): - - # Numbers - new_value = random.choice(choices_number) - - elif random.choice((True, False)) and value.isalpha(): - - # Letters - new_value = random.choice(choices_letter) - - elif random.choice((True, False)) and value.isalnum(): - - # Alphanumeric - new_value = random.choice(choices_alnum) - - else: - - # Default type - new_value = random.choice(choices_alnum + choices_letter + choices_number) - - # If we worked on a substring, apply changes to the whole string - if value != attrib_value: - # No ' around empty values - if new_value != "" and value != "": - new_value = "'" + new_value + "'" - # Apply changes - new_value = attrib_value.replace(unclean_value, new_value) - - # Log something - if self.verbose: - print( - "Fuzzing attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Modify the attribute - rand_elem.set(rand_attrib, new_value.decode("utf-8")) - - def __del_node_and_children(self): - - """High-level minimizing mutator - Delete a random node and its children (i.e. delete a random tree)""" - - self.__del_node(True) - - def __del_node_but_children(self): - - """High-level minimizing mutator - Delete a random node but its children (i.e. link them to the parent of the deleted node)""" - - self.__del_node(False) - - def __del_node(self, delete_children): - - """ Called by the __del_node_* mutators """ - - # Select a node to modify (but the root one) - (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True) - - # If the document includes only a top-level element - # Then we can't pick a element (given that "exclude_root_node = True") - - # Is the document deep enough? - if rand_elem is None: - if self.verbose: - print("Can't delete a node: document not deep enough!") - return - - # Log something - if self.verbose: - but_or_and = "and" if delete_children else "but" - print( - "Deleting tag #%i '%s' %s its children" - % (rand_elem_id, rand_elem.tag, but_or_and) - ) - - if delete_children is False: - # Link children of the random (soon to be deleted) node to its parent - for child in rand_elem: - rand_elem.getparent().append(child) - - # Remove the node - rand_elem.getparent().remove(rand_elem) - - def __del_content(self): - - """High-level minimizing mutator - Delete the attributes and children of a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Log something - if self.verbose: - print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag)) - - # Reset the node - rand_elem.clear() - - def __del_attribute(self): - - """High-level minimizing mutator - Delete a random attribute from a random node""" - - # Select a node to modify - (rand_elem_id, rand_elem) = self.__pick_element() - - # Get all the attributes - attribs = rand_elem.keys() - - # Is there attributes? - if len(attribs) < 1: - if self.verbose: - print("No attribute: can't delete!") - return - - # Pick a random attribute - rand_attrib_id = random.randint(0, len(attribs) - 1) - rand_attrib = attribs[rand_attrib_id] - - # Log something - if self.verbose: - print( - "Deleting attribute #%i '%s' of tag #%i '%s'" - % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag) - ) - - # Delete the attribute - rand_elem.attrib.pop(rand_attrib) - - def mutate(self, min=1, max=5): - - """ Execute some high-level mutators between $min and $max times, then some medium-level ones """ - - # High-level mutation - self.__exec_among(self, self.hl_mutators_all, min, max) diff --git a/utils/custom_mutators/common.py b/utils/custom_mutators/common.py deleted file mode 100644 index 44a5056a..00000000 --- a/utils/custom_mutators/common.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Module containing functions shared between multiple AFL modules - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -from __future__ import print_function -import random -import os -import re - - -def randel(l): - if not l: - return None - return l[random.randint(0, len(l) - 1)] - - -def randel_pop(l): - if not l: - return None - return l.pop(random.randint(0, len(l) - 1)) - - -def write_exc_example(data, exc): - exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc)) - - if not os.path.exists(exc_name): - with open(exc_name, "w") as f: - f.write(data) diff --git a/utils/custom_mutators/custom_mutator_helpers.h b/utils/custom_mutators/custom_mutator_helpers.h deleted file mode 100644 index 62e6efba..00000000 --- a/utils/custom_mutators/custom_mutator_helpers.h +++ /dev/null @@ -1,342 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include - -#define INITIAL_GROWTH_SIZE (64) - -#define RAND_BELOW(limit) (rand() % (limit)) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this fills in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -typedef struct { - -} afl_t; - -static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { - - static s8 interesting_8[] = {INTERESTING_8}; - static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; - static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - - switch (RAND_BELOW(12)) { - - case 0: { - - /* Flip a single bit somewhere. Spooky! */ - - s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); - - out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); - - break; - - } - - case 1: { - - /* Set byte to interesting value. */ - - u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; - out_buf[(RAND_BELOW(end - begin) + begin)] = val; - - break; - - } - - case 2: { - - /* Set word to interesting value, randomly choosing endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u16 *)(out_buf + byte_idx) = - interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; - break; - case 1: - *(u16 *)(out_buf + byte_idx) = - SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); - break; - - } - - break; - - } - - case 3: { - - /* Set dword to interesting value, randomly choosing endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u32 *)(out_buf + byte_idx) = - interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u32 *)(out_buf + byte_idx) = - SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 4: { - - /* Set qword to interesting value, randomly choosing endian. */ - - if (end - begin < 8) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 7) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u64 *)(out_buf + byte_idx) = - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u64 *)(out_buf + byte_idx) = SWAP64( - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 5: { - - /* Randomly subtract from byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 6: { - - /* Randomly add to byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 7: { - - /* Randomly subtract from word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 8: { - - /* Randomly add to word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 9: { - - /* Randomly subtract from dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 10: { - - /* Randomly add to dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 11: { - - /* Just set a random byte to a random value. Because, - why not. We use XOR with 1-255 to eliminate the - possibility of a no-op. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); - - break; - - } - - } - -} - -/* This function calculates the next power of 2 greater or equal its argument. - @return The rounded up power of 2 (if no overflow) or 0 on overflow. -*/ -static inline size_t next_pow2(size_t in) { - - if (in == 0 || in > (size_t)-1) - return 0; /* avoid undefined behaviour under-/overflow */ - size_t out = in - 1; - out |= out >> 1; - out |= out >> 2; - out |= out >> 4; - out |= out >> 8; - out |= out >> 16; - return out + 1; - -} - -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) return *buf; - - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); - - /* handle overflow */ - if (!next_size) { next_size = size_needed; } - - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; - - return *buf; - -} - -/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { - - void * scratch_buf = *buf1; - size_t scratch_size = *size1; - *buf1 = *buf2; - *size1 = *size2; - *buf2 = scratch_buf; - *size2 = scratch_size; - -} - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/utils/custom_mutators/example.c b/utils/custom_mutators/example.c deleted file mode 100644 index 23add128..00000000 --- a/utils/custom_mutators/example.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - New Custom Mutator for AFL++ - Written by Khaled Yakdan - Andrea Fioraldi - Shengtuo Hu - Dominik Maier -*/ - -// You need to use -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#define DATA_SIZE (100) - -static const char *commands[] = { - - "GET", - "PUT", - "DEL", - -}; - -typedef struct my_mutator { - - afl_t *afl; - - // any additional data here! - size_t trim_size_current; - int trimmming_steps; - int cur_step; - - // Reused buffers: - BUF_VAR(u8, fuzz); - BUF_VAR(u8, data); - BUF_VAR(u8, havoc); - BUF_VAR(u8, trim); - BUF_VAR(u8, post_process); - -} my_mutator_t; - -/** - * Initialize this custom mutator - * - * @param[in] afl a pointer to the internal state object. Can be ignored for - * now. - * @param[in] seed A seed for this mutator - the same seed should always mutate - * in the same way. - * @return Pointer to the data object this custom mutator instance should use. - * There may be multiple instances of this mutator in one afl-fuzz run! - * Return NULL on error. - */ -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); // needed also by surgical_havoc_mutate() - - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -/** - * Perform custom mutations on a given input - * - * (Optional for now. Required in the future) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to input data to be mutated - * @param[in] buf_size Size of input data - * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on - * error. - * @param[in] add_buf Buffer containing the additional test case - * @param[in] add_buf_size Size of the additional test case - * @param[in] max_size Maximum size of the mutated output. The mutation must not - * produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - // Make sure that the packet size does not exceed the maximum size expected by - // the fuzzer - size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size; - - // maybe_grow is optimized to be quick for reused buffers. - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - // Randomly select a command string to add as a header to the packet - memcpy(mutated_out, commands[rand() % 3], 3); - - // Mutate the payload of the packet - int i; - for (i = 0; i < 8; ++i) { - - // Randomly perform one of the (no len modification) havoc mutations - surgical_havoc_mutate(mutated_out, 3, mutated_size); - - } - - *out_buf = mutated_out; - return mutated_size; - -} - -/** - * A post-processing function to use right before AFL writes the test case to - * disk in order to execute the target. - * - * (Optional) If this functionality is not needed, simply don't define this - * function. - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Buffer containing the test case to be executed - * @param[in] buf_size Size of the test case - * @param[out] out_buf Pointer to the buffer containing the test case after - * processing. External library should allocate memory for out_buf. - * The buf pointer may be reused (up to the given buf_size); - * @return Size of the output buffer after processing or the needed amount. - * A return of 0 indicates an error. - */ -size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf, - size_t buf_size, uint8_t **out_buf) { - - uint8_t *post_process_buf = - maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5); - if (!post_process_buf) { - - perror("custom mutator realloc failed."); - *out_buf = NULL; - return 0; - - } - - memcpy(post_process_buf + 5, buf, buf_size); - post_process_buf[0] = 'A'; - post_process_buf[1] = 'F'; - post_process_buf[2] = 'L'; - post_process_buf[3] = '+'; - post_process_buf[4] = '+'; - - *out_buf = post_process_buf; - - return buf_size + 5; - -} - -/** - * This method is called at the start of each trimming operation and receives - * the initial buffer. It should return the amount of iteration steps possible - * on this input (e.g. if your input has n elements and you want to remove - * them one by one, return n, if you do a binary search, return log(n), - * and so on...). - * - * If your trimming algorithm doesn't allow you to determine the amount of - * (remaining) steps easily (esp. while running), then you can alternatively - * return 1 here and always return 0 in post_trim until you are finished and - * no steps remain. In that case, returning 1 in post_trim will end the - * trimming routine. The whole current index/max iterations stuff is only used - * to show progress. - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param buf Buffer containing the test case - * @param buf_size Size of the test case - * @return The amount of possible iteration steps to trim the input. - * negative on error. - */ -int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, - size_t buf_size) { - - // We simply trim once - data->trimmming_steps = 1; - - data->cur_step = 0; - - if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) { - - perror("init_trim grow"); - return -1; - - } - - memcpy(data->trim_buf, buf, buf_size); - - data->trim_size_current = buf_size; - - return data->trimmming_steps; - -} - -/** - * This method is called for each trimming operation. It doesn't have any - * arguments because we already have the initial buffer from init_trim and we - * can memorize the current state in *data. This can also save - * reparsing steps for each iteration. It should return the trimmed input - * buffer, where the returned data must not exceed the initial input data in - * length. Returning anything that is larger than the original data (passed - * to init_trim) will result in a fatal abort of AFLFuzz. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[out] out_buf Pointer to the buffer containing the trimmed test case. - * External library should allocate memory for out_buf. - * AFL++ will not release the memory after saving the test case. - * Keep a ref in *data. - * *out_buf = NULL is treated as error. - * @return Pointer to the size of the trimmed test case - */ -size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) { - - *out_buf = data->trim_buf; - - // Remove the last byte of the trimming input - return data->trim_size_current - 1; - -} - -/** - * This method is called after each trim operation to inform you if your - * trimming step was successful or not (in terms of coverage). If you receive - * a failure here, you should reset your input to the last known good state. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param success Indicates if the last trim operation was successful. - * @return The next trim iteration index (from 0 to the maximum amount of - * steps returned in init_trim). negative ret on failure. - */ -int32_t afl_custom_post_trim(my_mutator_t *data, int success) { - - if (success) { - - ++data->cur_step; - return data->cur_step; - - } - - return data->trimmming_steps; - -} - -/** - * Perform a single custom mutation on a given input. - * This mutation is stacked with the other muatations in havoc. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param[in] buf Pointer to the input data to be mutated and the mutated - * output - * @param[in] buf_size Size of input data - * @param[out] out_buf The output buffer. buf can be reused, if the content - * fits. *out_buf = NULL is treated as error. - * @param[in] max_size Maximum size of the mutated output. The mutation must - * not produce data larger than max_size. - * @return Size of the mutated output. - */ -size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size, - u8 **out_buf, size_t max_size) { - - if (buf_size == 0) { - - *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1); - if (!*out_buf) { - - perror("custom havoc: maybe_grow"); - return 0; - - } - - **out_buf = rand() % 256; - buf_size = 1; - - } else { - - // We reuse buf here. It's legal and faster. - *out_buf = buf; - - } - - size_t victim = rand() % buf_size; - (*out_buf)[victim] += rand() % 10; - - return buf_size; - -} - -/** - * Return the probability (in percentage) that afl_custom_havoc_mutation - * is called in havoc. By default it is 6 %. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @return The probability (0-100). - */ -uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) { - - return 5; // 5 % - -} - -/** - * Determine whether the fuzzer should fuzz the queue entry or not. - * - * (Optional) - * - * @param[in] data pointer returned in afl_custom_init for this fuzz case - * @param filename File name of the test case in the queue entry - * @return Return True(1) if the fuzzer will fuzz the queue entry, and - * False(0) otherwise. - */ -uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) { - - return 1; - -} - -/** - * Allow for additional analysis (e.g. calling a different tool that does a - * different kind of coverage and saves this for the custom mutator). - * - * (Optional) - * - * @param data pointer returned in afl_custom_init for this fuzz case - * @param filename_new_queue File name of the new queue entry - * @param filename_orig_queue File name of the original queue entry - */ -void afl_custom_queue_new_entry(my_mutator_t * data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { - - /* Additional analysis on the original or new test case */ - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->post_process_buf); - free(data->havoc_buf); - free(data->data_buf); - free(data->fuzz_buf); - free(data->trim_buf); - free(data); - -} - diff --git a/utils/custom_mutators/example.py b/utils/custom_mutators/example.py deleted file mode 100644 index 3a6d22e4..00000000 --- a/utils/custom_mutators/example.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Example Python Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -import random - - -COMMANDS = [ - b"GET", - b"PUT", - b"DEL", - b"AAAAAAAAAAAAAAAAA", -] - - -def init(seed): - """ - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - """ - random.seed(seed) - - -def deinit(): - pass - - -def fuzz(buf, add_buf, max_size): - """ - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - """ - ret = bytearray(100) - - ret[:3] = random.choice(COMMANDS) - - return ret - - -# Uncomment and implement the following methods if you want to use a custom -# trimming algorithm. See also the documentation for a better API description. - -# def init_trim(buf): -# ''' -# Called per trimming iteration. -# -# @type buf: bytearray -# @param buf: The buffer that should be trimmed. -# -# @rtype: int -# @return: The maximum number of trimming steps. -# ''' -# global ... -# -# # Initialize global variables -# -# # Figure out how many trimming steps are possible. -# # If this is not possible for your trimming, you can -# # return 1 instead and always return 0 in post_trim -# # until you are done (then you return 1). -# -# return steps -# -# def trim(): -# ''' -# Called per trimming iteration. -# -# @rtype: bytearray -# @return: A new bytearray containing the trimmed data. -# ''' -# global ... -# -# # Implement the actual trimming here -# -# return bytearray(...) -# -# def post_trim(success): -# ''' -# Called after each trimming operation. -# -# @type success: bool -# @param success: Indicates if the last trim operation was successful. -# -# @rtype: int -# @return: The next trim index (0 to max number of steps) where max -# number of steps indicates the trimming is done. -# ''' -# global ... -# -# if not success: -# # Restore last known successful input, determine next index -# else: -# # Just determine the next index, based on what was successfully -# # removed in the last step -# -# return next_index -# -# def post_process(buf): -# ''' -# Called just before the execution to write the test case in the format -# expected by the target -# -# @type buf: bytearray -# @param buf: The buffer containing the test case to be executed -# -# @rtype: bytearray -# @return: The buffer containing the test case after -# ''' -# return buf -# -# def havoc_mutation(buf, max_size): -# ''' -# Perform a single custom mutation on a given input. -# -# @type buf: bytearray -# @param buf: The buffer that should be mutated. -# -# @type max_size: int -# @param max_size: Maximum size of the mutated output. The mutation must not -# produce data larger than max_size. -# -# @rtype: bytearray -# @return: A new bytearray containing the mutated data -# ''' -# return mutated_buf -# -# def havoc_mutation_probability(): -# ''' -# Called for each `havoc_mutation`. Return the probability (in percentage) -# that `havoc_mutation` is called in havoc. Be default it is 6%. -# -# @rtype: int -# @return: The probability (0-100) -# ''' -# return prob -# -# def queue_get(filename): -# ''' -# Called at the beginning of each fuzz iteration to determine whether the -# test case should be fuzzed -# -# @type filename: str -# @param filename: File name of the test case in the current queue entry -# -# @rtype: bool -# @return: Return True if the custom mutator decides to fuzz the test case, -# and False otherwise -# ''' -# return True -# -# def queue_new_entry(filename_new_queue, filename_orig_queue): -# ''' -# Called after adding a new test case to the queue -# -# @type filename_new_queue: str -# @param filename_new_queue: File name of the new queue entry -# -# @type filename_orig_queue: str -# @param filename_orig_queue: File name of the original queue entry -# ''' -# pass diff --git a/utils/custom_mutators/post_library_gif.so.c b/utils/custom_mutators/post_library_gif.so.c deleted file mode 100644 index ac10f409..00000000 --- a/utils/custom_mutators/post_library_gif.so.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - american fuzzy lop++ - postprocessor library example - -------------------------------------------------- - - Originally written by Michal Zalewski - Edited by Dominik Maier, 2020 - - Copyright 2015 Google Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - Postprocessor libraries can be passed to afl-fuzz to perform final cleanup - of any mutated test cases - for example, to fix up checksums in PNG files. - - Please heed the following warnings: - - 1) In almost all cases, it is more productive to comment out checksum logic - in the targeted binary (as shown in ../libpng_no_checksum/). One possible - exception is the process of fuzzing binary-only software in QEMU mode. - - 2) The use of postprocessors for anything other than checksums is - questionable and may cause more harm than good. AFL is normally pretty good - about dealing with length fields, magic values, etc. - - 3) Postprocessors that do anything non-trivial must be extremely robust to - gracefully handle malformed data and other error conditions - otherwise, - they will crash and take afl-fuzz down with them. Be wary of reading past - *len and of integer overflows when calculating file offsets. - - In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really, - honestly know what you're doing =) - - With that out of the way: the postprocessor library is passed to afl-fuzz - via AFL_POST_LIBRARY. The library must be compiled with: - - gcc -shared -Wall -O3 post_library.so.c -o post_library.so - - AFL will call the afl_custom_post_process() function for every mutated output - buffer. From there, you have three choices: - - 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` - and return the original `len`. - - 2) If you want to skip this test case altogether and have AFL generate a - new one, return 0 or set `*out_buf = NULL`. - Use this sparingly - it's faster than running the target program - with patently useless inputs, but still wastes CPU time. - - 3) If you want to modify the test case, allocate an appropriately-sized - buffer, move the data into that buffer, make the necessary changes, and - then return the new pointer as out_buf. Return an appropriate len - afterwards. - - Note that the buffer will *not* be freed for you. To avoid memory leaks, - you need to free it or reuse it on subsequent calls (as shown below). - - *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - - Aight. The example below shows a simple postprocessor that tries to make - sure that all input files start with "GIF89a". - - PS. If you don't like C, you can try out the unix-based wrapper from - Ben Nagy instead: https://github.com/bnagy/aflfix - - */ - -#include -#include -#include - -/* Header that must be present at the beginning of every test case: */ - -#define HEADER "GIF89a" - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -/* The actual postprocessor routine called by afl-fuzz: */ - -size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf, - unsigned int len, unsigned char **out_buf) { - - /* Skip execution altogether for buffers shorter than 6 bytes (just to - show how it's done). We can trust len to be sane. */ - - if (len < strlen(HEADER)) return 0; - - /* Do nothing for buffers that already start with the expected header. */ - - if (!memcmp(in_buf, HEADER, strlen(HEADER))) { - - *out_buf = in_buf; - return len; - - } - - /* Allocate memory for new buffer, reusing previous allocation if - possible. */ - - *out_buf = realloc(data->buf, len); - - /* If we're out of memory, the most graceful thing to do is to return the - original buffer and give up on modifying it. Let AFL handle OOM on its - own later on. */ - - if (!*out_buf) { - - *out_buf = in_buf; - return len; - - } - - /* Copy the original data to the new location. */ - - memcpy(*out_buf, in_buf, len); - - /* Insert the new header. */ - - memcpy(*out_buf, HEADER, strlen(HEADER)); - - /* Return the new len. It hasn't changed, so it's just len. */ - - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/utils/custom_mutators/post_library_png.so.c b/utils/custom_mutators/post_library_png.so.c deleted file mode 100644 index 941f7e55..00000000 --- a/utils/custom_mutators/post_library_png.so.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - american fuzzy lop++ - postprocessor for PNG - ------------------------------------------ - - Originally written by Michal Zalewski - - Copyright 2015 Google Inc. All rights reserved. - Adapted to the new API, 2020 by Dominik Maier - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - See post_library.so.c for a general discussion of how to implement - postprocessors. This specific postprocessor attempts to fix up PNG - checksums, providing a slightly more complicated example than found - in post_library.so.c. - - Compile with: - - gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz - - */ - -#include -#include -#include -#include -#include - -#include - -/* A macro to round an integer up to 4 kB. */ - -#define UP4K(_i) ((((_i) >> 12) + 1) << 12) - -typedef struct post_state { - - unsigned char *buf; - size_t size; - -} post_state_t; - -void *afl_custom_init(void *afl) { - - post_state_t *state = malloc(sizeof(post_state_t)); - if (!state) { - - perror("malloc"); - return NULL; - - } - - state->buf = calloc(sizeof(unsigned char), 4096); - if (!state->buf) { - - free(state); - perror("calloc"); - return NULL; - - } - - return state; - -} - -size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf, - unsigned int len, - const unsigned char **out_buf) { - - unsigned char *new_buf = (unsigned char *)in_buf; - unsigned int pos = 8; - - /* Don't do anything if there's not enough room for the PNG header - (8 bytes). */ - - if (len < 8) { - - *out_buf = in_buf; - return len; - - } - - /* Minimum size of a zero-length PNG chunk is 12 bytes; if we - don't have that, we can bail out. */ - - while (pos + 12 <= len) { - - unsigned int chunk_len, real_cksum, file_cksum; - - /* Chunk length is the first big-endian dword in the chunk. */ - - chunk_len = ntohl(*(uint32_t *)(in_buf + pos)); - - /* Bail out if chunk size is too big or goes past EOF. */ - - if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break; - - /* Chunk checksum is calculated for chunk ID (dword) and the actual - payload. */ - - real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4)); - - /* The in-file checksum is the last dword past the chunk data. */ - - file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len); - - /* If the checksums do not match, we need to fix the file. */ - - if (real_cksum != file_cksum) { - - /* First modification? Make a copy of the input buffer. Round size - up to 4 kB to minimize the number of reallocs needed. */ - - if (new_buf == in_buf) { - - if (len <= data->size) { - - new_buf = data->buf; - - } else { - - new_buf = realloc(data->buf, UP4K(len)); - if (!new_buf) { - - *out_buf = in_buf; - return len; - - } - - data->buf = new_buf; - data->size = UP4K(len); - memcpy(new_buf, in_buf, len); - - } - - } - - *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum; - - } - - /* Skip the entire chunk and move to the next one. */ - - pos += 12 + chunk_len; - - } - - *out_buf = new_buf; - return len; - -} - -/* Gets called afterwards */ -void afl_custom_deinit(post_state_t *data) { - - free(data->buf); - free(data); - -} - diff --git a/utils/custom_mutators/simple-chunk-replace.py b/utils/custom_mutators/simple-chunk-replace.py deleted file mode 100644 index c57218dd..00000000 --- a/utils/custom_mutators/simple-chunk-replace.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -""" -Simple Chunk Cross-Over Replacement Module for AFLFuzz - -@author: Christian Holler (:decoder) - -@license: - -This Source Code Form is subject to the terms of the Mozilla Public -License, v. 2.0. If a copy of the MPL was not distributed with this -file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@contact: choller@mozilla.com -""" - -import random - - -def init(seed): - """ - Called once when AFLFuzz starts up. Used to seed our RNG. - - @type seed: int - @param seed: A 32-bit random value - """ - # Seed our RNG - random.seed(seed) - - -def fuzz(buf, add_buf, max_size): - """ - Called per fuzzing iteration. - - @type buf: bytearray - @param buf: The buffer that should be mutated. - - @type add_buf: bytearray - @param add_buf: A second buffer that can be used as mutation source. - - @type max_size: int - @param max_size: Maximum size of the mutated output. The mutation must not - produce data larger than max_size. - - @rtype: bytearray - @return: A new bytearray containing the mutated data - """ - # Make a copy of our input buffer for returning - ret = bytearray(buf) - - # Take a random fragment length between 2 and 32 (or less if add_buf is shorter) - fragment_len = random.randint(1, min(len(add_buf), 32)) - - # Determine a random source index where to take the data chunk from - rand_src_idx = random.randint(0, len(add_buf) - fragment_len) - - # Determine a random destination index where to put the data chunk - rand_dst_idx = random.randint(0, len(buf)) - - # Make the chunk replacement - ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[ - rand_src_idx : rand_src_idx + fragment_len - ] - - # Return data - return ret diff --git a/utils/custom_mutators/simple_example.c b/utils/custom_mutators/simple_example.c deleted file mode 100644 index d888ec1f..00000000 --- a/utils/custom_mutators/simple_example.c +++ /dev/null @@ -1,74 +0,0 @@ -// This simple example just creates random buffer <= 100 filled with 'A' -// needs -I /path/to/AFLplusplus/include -#include "custom_mutator_helpers.h" - -#include -#include -#include -#include - -#ifndef _FIXED_CHAR - #define _FIXED_CHAR 0x41 -#endif - -typedef struct my_mutator { - - afl_t *afl; - - // Reused buffers: - BUF_VAR(u8, fuzz); - -} my_mutator_t; - -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { - - srand(seed); - my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); - if (!data) { - - perror("afl_custom_init alloc"); - return NULL; - - } - - data->afl = afl; - - return data; - -} - -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, - size_t add_buf_size, // add_buf can be NULL - size_t max_size) { - - int size = (rand() % 100) + 1; - if (size > max_size) size = max_size; - u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size); - if (!mutated_out) { - - *out_buf = NULL; - perror("custom mutator allocation (maybe_grow)"); - return 0; /* afl-fuzz will very likely error out after this. */ - - } - - memset(mutated_out, _FIXED_CHAR, size); - - *out_buf = mutated_out; - return size; - -} - -/** - * Deinitialize everything - * - * @param data The data ptr from afl_custom_init - */ -void afl_custom_deinit(my_mutator_t *data) { - - free(data->fuzz_buf); - free(data); - -} - diff --git a/utils/custom_mutators/wrapper_afl_min.py b/utils/custom_mutators/wrapper_afl_min.py deleted file mode 100644 index 5cd60031..00000000 --- a/utils/custom_mutators/wrapper_afl_min.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python - -from XmlMutatorMin import XmlMutatorMin - -# Default settings (production mode) - -__mutator__ = None -__seed__ = "RANDOM" -__log__ = False -__log_file__ = "wrapper.log" - - -# AFL functions -def log(text): - """ - Logger - """ - - global __seed__ - global __log__ - global __log_file__ - - if __log__: - with open(__log_file__, "a") as logf: - logf.write("[%s] %s\n" % (__seed__, text)) - - -def init(seed): - """ - Called once when AFL starts up. Seed is used to identify the AFL instance in log files - """ - - global __mutator__ - global __seed__ - - # Get the seed - __seed__ = seed - - # Create a global mutation class - try: - __mutator__ = XmlMutatorMin(__seed__, verbose=__log__) - log("init(): Mutator created") - except RuntimeError as e: - log("init(): Can't create mutator: %s" % e.message) - - -def fuzz(buf, add_buf, max_size): - """ - Called for each fuzzing iteration. - """ - - global __mutator__ - - # Do we have a working mutator object? - if __mutator__ is None: - log("fuzz(): Can't fuzz, no mutator available") - return buf - - # Try to use the AFL buffer - via_buffer = True - - # Interpret the AFL buffer (an array of bytes) as a string - if via_buffer: - try: - buf_str = str(buf) - log("fuzz(): AFL buffer converted to a string") - except Exception: - via_buffer = False - log("fuzz(): Can't convert AFL buffer to a string") - - # Load XML from the AFL string - if via_buffer: - try: - __mutator__.init_from_string(buf_str) - log( - "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" - % len(buf_str) - ) - except Exception: - via_buffer = False - log("fuzz(): Can't initialize mutator with AFL buffer") - - # If init from AFL buffer wasn't succesful - if not via_buffer: - log("fuzz(): Returning unmodified AFL buffer") - return buf - - # Sucessful initialization -> mutate - try: - __mutator__.mutate(max=5) - log("fuzz(): Input mutated") - except Exception: - log("fuzz(): Can't mutate input => returning buf") - return buf - - # Convert mutated data to a array of bytes - try: - data = bytearray(__mutator__.save_to_string()) - log("fuzz(): Mutated data converted as bytes") - except Exception: - log("fuzz(): Can't convert mutated data to bytes => returning buf") - return buf - - # Everything went fine, returning mutated content - log("fuzz(): Returning %d bytes" % len(data)) - return data - - -# Main (for debug) -if __name__ == "__main__": - - __log__ = True - __log_file__ = "/dev/stdout" - __seed__ = "RANDOM" - - init(__seed__) - - in_1 = bytearray( - "ffffzzzzzzzzzzzz" - ) - in_2 = bytearray("") - out = fuzz(in_1, in_2) - print(out) diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c index 1b247c86..dde78f7b 100644 --- a/utils/libdislocator/libdislocator.so.c +++ b/utils/libdislocator/libdislocator.so.c @@ -144,8 +144,8 @@ typedef struct { /* Configurable stuff (use AFL_LD_* to set): */ -static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */ -static u8 alloc_verbose, /* Additional debug messages */ +static size_t max_mem = MAX_ALLOC; /* Max heap usage to permit */ +static u8 alloc_verbose, /* Additional debug messages */ hard_fail, /* abort() when max_mem exceeded? */ no_calloc_over, /* abort() on calloc() overflows? */ align_allocations; /* Force alignment to sizeof(void*) */ @@ -154,7 +154,7 @@ static u8 alloc_verbose, /* Additional debug messages */ #define __thread #warning no thread support available #endif -static __thread size_t total_mem; /* Currently allocated mem */ +static _Atomic size_t total_mem; /* Currently allocated mem */ static __thread u32 call_depth; /* To avoid recursion via fprintf() */ static u32 alloc_canary; @@ -172,9 +172,9 @@ static void *__dislocator_alloc(size_t len) { if (total_mem + len > max_mem || total_mem + len < total_mem) { - if (hard_fail) FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024); + if (hard_fail) FATAL("total allocs exceed %zu MB", max_mem / 1024 / 1024); - DEBUGF("total allocs exceed %u MB, returning NULL", max_mem / 1024 / 1024); + DEBUGF("total allocs exceed %zu MB, returning NULL", max_mem / 1024 / 1024); return NULL; @@ -500,19 +500,20 @@ size_t malloc_usable_size(const void *ptr) { __attribute__((constructor)) void __dislocator_init(void) { - u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB"); + char *tmp = getenv("AFL_LD_LIMIT_MB"); if (tmp) { - u8 *tok; - s32 mmem = (s32)strtol((char *)tmp, (char **)&tok, 10); - if (*tok != '\0' || errno == ERANGE) FATAL("Bad value for AFL_LD_LIMIT_MB"); + char * tok; + unsigned long long mmem = strtoull(tmp, &tok, 10); + if (*tok != '\0' || errno == ERANGE || mmem > SIZE_MAX / 1024 / 1024) + FATAL("Bad value for AFL_LD_LIMIT_MB"); max_mem = mmem * 1024 * 1024; } alloc_canary = ALLOC_CANARY; - tmp = (u8 *)getenv("AFL_RANDOM_ALLOC_CANARY"); + tmp = getenv("AFL_RANDOM_ALLOC_CANARY"); if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary)); diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp index b2066cc8..182a014b 100755 --- a/utils/qbdi_mode/template.cpp +++ b/utils/qbdi_mode/template.cpp @@ -25,7 +25,7 @@ #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) #define INC_AFL_AREA(loc) \ asm volatile( \ - "incb (%0, %1, 1)\n" \ + "addb $1, (%0, %1, 1)\n" \ "adcb $0, (%0, %1, 1)\n" \ : /* no out */ \ : "r"(afl_area_ptr), "r"(loc) \ diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c index c1c6642f..14b2ed85 100644 --- a/utils/qemu_persistent_hook/read_into_rdi.c +++ b/utils/qemu_persistent_hook/read_into_rdi.c @@ -3,12 +3,12 @@ #include #include -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) #define h2g(x) ((uint64_t)(x)-guest_base) +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + // In this example the register RDI is pointing to the memory location // of the target buffer, and the length of the input is in RSI. // This can be seen with a debugger, e.g. gdb (and "disass main") @@ -19,11 +19,11 @@ void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, memcpy(g2h(regs->rdi), input_buf, input_buf_len); regs->rsi = input_buf_len; +} + #undef g2h #undef h2g -} - int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use -- cgit 1.4.1 From fd077e86bdfb73f1aa8432be547b1e8477883abb Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Mon, 10 May 2021 18:20:28 -0400 Subject: OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory --- docs/INSTALL.md | 35 +++++++++++++++++++++++++++++++++++ src/afl-cc.c | 12 ++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/INSTALL.md b/docs/INSTALL.md index e3c06c9d..80d452f7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The comes with Xcode is missing some of the essential headers and helper tools. See README.llvm.md for advice on how to build the compiler from scratch. +MacOS X supports SYSV shared memory used by AFL's instrumentation, but the +default settings aren't usable with AFL++. The default settings on 10.14 seem +to be: + +```bash +$ ipcs -M +IPC status from as of XXX +shminfo: + shmmax: 4194304 (max shared memory segment size) + shmmin: 1 (min shared memory segment size) + shmmni: 32 (max number of shared memory identifiers) + shmseg: 8 (max shared memory segments per process) + shmall: 1024 (max amount of shared memory in pages) +``` + +To temporarily change your settings to something minimally usable with AFL++, +run these commands as root: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmall=4096 +``` + +If you're running more than one instance of AFL you likely want to make `shmall` +bigger and increase `shmseg` as well: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmseg=48 +sysctl kern.sysv.shmall=98304 +``` + +See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for +these settings and how to make them permanent. + ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to diff --git a/src/afl-cc.c b/src/afl-cc.c index 09009334..c1050355 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,7 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) - compiler_mode = GCC; + #ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; + #else + compiler_mode = GCC; + #endif else if (have_lto) compiler_mode = LTO; else @@ -1596,7 +1601,10 @@ int main(int argc, char **argv, char **envp) { } - if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; } + if (compiler_mode == CLANG) { + instrument_mode = INSTRUMENT_CLANG; + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { -- cgit 1.4.1 From 72ca9b4684981ce2b807e4efd218bd1924f3e6b1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 11 May 2021 22:06:37 +0200 Subject: fix a few cur_time uses --- docs/Changelog.md | 1 + src/afl-cc.c | 16 +++++++++------- src/afl-fuzz-one.c | 6 +++--- src/afl-fuzz-stats.c | 5 +++-- src/afl-fuzz.c | 6 ++++-- 5 files changed, 20 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index ceb02bb9..e4c02921 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! diff --git a/src/afl-cc.c b/src/afl-cc.c index c1050355..ff7b5219 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,12 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) - #ifdef __APPLE__ - // on OSX clang masquerades as GCC - compiler_mode = CLANG; - #else - compiler_mode = GCC; - #endif +#ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; +#else + compiler_mode = GCC; +#endif else if (have_lto) compiler_mode = LTO; else @@ -1602,8 +1602,10 @@ int main(int argc, char **argv, char **envp) { } if (compiler_mode == CLANG) { + instrument_mode = INSTRUMENT_CLANG; - setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4eeb93de..4a3e7f33 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2013,7 +2013,7 @@ havoc_stage: } - if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ @@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 313263f9..4884b942 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -368,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, afl->plot_prev_uh == afl->unique_hangs && afl->plot_prev_md == afl->max_depth && afl->plot_prev_ed == afl->fsrv.total_execs) || - !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { + !afl->queue_cycle || + get_cur_time() - afl->start_time <= 60000))) { return; @@ -393,7 +394,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(afl->fsrv.plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%u\n", - (afl->prev_run_time + get_cur_time() - afl->start_time), + ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000), afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8de3ed6b..094fd161 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1940,8 +1940,10 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (unlikely(afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600)) { + if (unlikely(afl->queued_paths == prev_queued + /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >= + 3600 */ + )) { if (afl->use_splicing) { -- cgit 1.4.1 From 47e22e8d8d383078989906c6fe54a9ec4deff8c1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 16:52:52 +0200 Subject: no core dumps --- docs/Changelog.md | 1 + src/afl-forkserver.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index e4c02921..4fa70bfd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,6 +29,7 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a07e78b4..0286ab47 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -451,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered before the dump is complete. */ - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + if (!fsrv->debug) { + + r.rlim_max = r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + } /* Isolate the process and configure standard descriptors. If out_file is specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ -- cgit 1.4.1 From ccf739f8801c373fe2aa1bb709ffd697cfe2a3e6 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:16:41 +0200 Subject: AFL_PRINT_FILENAMES added --- afl-cmin | 2 ++ docs/Changelog.md | 1 + docs/env_variables.md | 3 ++ src/afl-showmap.c | 82 ++++++++++++++++++++++++++++----------------------- 4 files changed, 51 insertions(+), 37 deletions(-) (limited to 'docs') diff --git a/afl-cmin b/afl-cmin index 3f3a7517..adcbb221 100755 --- a/afl-cmin +++ b/afl-cmin @@ -123,6 +123,8 @@ function usage() { "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ +"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ + "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index 4fa70bfd..67ab9d5e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -50,6 +50,7 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index 8879db72..99568146 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -567,6 +567,9 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. + - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. + This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting. + ## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 41a62108..336ac126 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -76,17 +76,18 @@ static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; -static u8 quiet_mode, /* Hide non-essential messages? */ +static bool quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1, /* remove shmem? */ + remove_shm = true, /* remove shmem? */ collect_coverage, /* collect coverage */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ - debug; /* debug mode */ + debug, /* debug mode */ + print_filenames; /* print the current filename */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -320,11 +321,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -335,11 +336,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { - child_crashed = 1; + child_crashed = true; } else { - child_crashed = 0; + child_crashed = false; } @@ -375,6 +376,8 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { + if (print_filenames) { SAYF("Processing %s\n", in_file); } + struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -515,11 +518,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -529,7 +532,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) { - child_crashed = 1; + child_crashed = true; } @@ -559,7 +562,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static void handle_stop_sig(int sig) { (void)sig; - stop_soon = 1; + stop_soon = true; afl_fsrv_killall(); } @@ -742,6 +745,8 @@ static void usage(u8 *argv0) { "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " + "printed to stdout\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -755,14 +760,17 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt, i; + bool mem_limit_given = false, timeout_given = false, unicorn_mode = false, + use_wine = false; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); afl_forkserver_t fsrv_var = {0}; - if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_DEBUG")) { debug = true; } + if (getenv("AFL_PRINT_FILENAMES")) { print_filenames = true; } + fsrv = &fsrv_var; afl_fsrv_init(fsrv); map_size = get_map_size(); @@ -770,19 +778,19 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } + if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { case 's': - no_classify = 1; + no_classify = true; break; case 'C': - collect_coverage = 1; - quiet_mode = 1; + collect_coverage = true; + quiet_mode = true; break; case 'i': @@ -801,7 +809,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 suffix = 'M'; if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; + mem_limit_given = true; if (!optarg) { FATAL("Wrong usage of -m"); } @@ -862,7 +870,7 @@ int main(int argc, char **argv_orig, char **envp) { case 't': if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; + timeout_given = true; if (!optarg) { FATAL("Wrong usage of -t"); } @@ -884,12 +892,12 @@ int main(int argc, char **argv_orig, char **envp) { if (edges_only) { FATAL("Multiple -e options not supported"); } if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); } - edges_only = 1; + edges_only = true; break; case 'q': - quiet_mode = 1; + quiet_mode = true; break; case 'Z': @@ -897,8 +905,8 @@ int main(int argc, char **argv_orig, char **envp) { /* This is an undocumented option to write data in the syntax expected by afl-cmin. Nobody else should have any use for this. */ - cmin_mode = 1; - quiet_mode = 1; + cmin_mode = true; + quiet_mode = true; break; case 'A': @@ -910,7 +918,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } - fsrv->frida_mode = 1; + fsrv->frida_mode = true; break; @@ -918,21 +926,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - fsrv->qemu_mode = 1; + fsrv->qemu_mode = true; break; case 'U': if (unicorn_mode) { FATAL("Multiple -U options not supported"); } - unicorn_mode = 1; + unicorn_mode = true; break; case 'W': /* Wine+QEMU mode */ if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; + fsrv->qemu_mode = true; + use_wine = true; break; @@ -941,20 +949,20 @@ int main(int argc, char **argv_orig, char **envp) { /* Secret undocumented mode. Writes output in raw binary format similar to that dumped by afl-fuzz in cmplog_mode = 0; u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1); - shm_fuzz->shmemfuzz_mode = 1; + shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } #ifdef USEMMAP setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1); @@ -1073,7 +1081,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv(SHM_FUZZ_ENV_VAR, shm_str, 1); ck_free(shm_str); #endif - fsrv->support_shmem_fuzz = 1; + fsrv->support_shmem_fuzz = true; fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); @@ -1125,7 +1133,7 @@ int main(int argc, char **argv_orig, char **envp) { struct stat statbuf; #endif - if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1; + if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -1164,8 +1172,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((coverage_map = (u8 *)malloc(map_size)) == NULL) FATAL("coult not grab memory"); - edges_only = 0; - raw_instr_output = 1; + edges_only = false; + raw_instr_output = true; } -- cgit 1.4.1 From fa63f2652dbcc6016ff5cf4bd8ca0d14954ae769 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:30:37 +0200 Subject: more documentation for AFL_EXIT_ON_TIME --- docs/Changelog.md | 2 ++ docs/env_variables.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 67ab9d5e..1114a834 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,6 +33,8 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after + no new paths have been found for n seconds - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 99568146..c3efa0c0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -285,8 +285,8 @@ checks or alter some of the more exotic semantics of the tool: convenient for some types of automated jobs. - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were - found within a specified period of time. May be convenient for some - types of automated jobs. + found within a specified period of time (in seconds). May be convenient + for some types of automated jobs. - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. -- cgit 1.4.1 From da2d4d8258d725f79c2daa22bf3b1a59c593e472 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 20 May 2021 11:14:46 +0200 Subject: Push to stable (#927) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza --- .github/workflows/ci.yml | 2 +- README.md | 7 +- afl-cmin | 2 + docs/Changelog.md | 5 + docs/INSTALL.md | 35 +++ docs/env_variables.md | 7 +- frida_mode/GNUmakefile | 12 +- frida_mode/Makefile | 4 + frida_mode/README.md | 82 +++++-- frida_mode/include/asan.h | 13 + frida_mode/include/ctx.h | 11 + frida_mode/include/frida_cmplog.h | 2 +- frida_mode/src/asan/asan.c | 24 ++ frida_mode/src/asan/asan_arm.c | 28 +++ frida_mode/src/asan/asan_arm64.c | 28 +++ frida_mode/src/asan/asan_x64.c | 93 +++++++ frida_mode/src/asan/asan_x86.c | 93 +++++++ frida_mode/src/cmplog/cmplog.c | 6 +- frida_mode/src/cmplog/cmplog_x64.c | 174 ++++---------- frida_mode/src/cmplog/cmplog_x86.c | 266 ++++++++++++++++++++- frida_mode/src/ctx/ctx_x64.c | 114 +++++++++ frida_mode/src/ctx/ctx_x86.c | 81 +++++++ frida_mode/src/instrument/instrument.c | 15 +- frida_mode/src/instrument/instrument_arm32.c | 3 + frida_mode/src/instrument/instrument_x86.c | 66 ++++- frida_mode/src/lib/lib.c | 15 +- frida_mode/src/main.c | 37 ++- frida_mode/src/persistent/persistent_x86.c | 233 +++++++++++++++++- frida_mode/src/stalker.c | 2 + frida_mode/test/cmplog/GNUmakefile | 43 ++-- frida_mode/test/cmplog/Makefile | 12 +- frida_mode/test/cmplog/cmplog.c | 100 ++++++++ frida_mode/test/entry_point/GNUmakefile | 23 +- frida_mode/test/entry_point/Makefile | 6 +- frida_mode/test/entry_point/testinstr.c | 2 + frida_mode/test/exe/GNUmakefile | 9 +- frida_mode/test/exe/Makefile | 6 +- frida_mode/test/fasan/GNUmakefile | 159 ++++++++++++ frida_mode/test/fasan/Makefile | 22 ++ frida_mode/test/fasan/test.c | 90 +++++++ frida_mode/test/png/GNUmakefile | 9 +- frida_mode/test/png/Makefile | 6 +- frida_mode/test/png/persistent/GNUmakefile | 23 +- frida_mode/test/png/persistent/Makefile | 6 +- frida_mode/test/png/persistent/get_symbol_addr.py | 2 +- frida_mode/test/png/persistent/hook/GNUmakefile | 53 +++- frida_mode/test/png/persistent/hook/Makefile | 12 +- .../png/persistent/hook/aflpp_qemu_driver_hook.c | 97 ++++++++ frida_mode/test/testinstr/GNUmakefile | 15 +- frida_mode/test/testinstr/Makefile | 9 +- include/envs.h | 2 + include/forkserver.h | 2 + qemu_mode/libqasan/hooks.c | 10 +- qemu_mode/libqasan/libqasan.c | 11 +- src/afl-cc.c | 12 +- src/afl-forkserver.c | 8 +- src/afl-fuzz-init.c | 18 +- src/afl-fuzz-one.c | 6 +- src/afl-fuzz-stats.c | 5 +- src/afl-fuzz.c | 107 +++++++-- src/afl-showmap.c | 100 +++++--- 61 files changed, 2130 insertions(+), 315 deletions(-) create mode 100644 frida_mode/include/asan.h create mode 100644 frida_mode/include/ctx.h create mode 100644 frida_mode/src/asan/asan.c create mode 100644 frida_mode/src/asan/asan_arm.c create mode 100644 frida_mode/src/asan/asan_arm64.c create mode 100644 frida_mode/src/asan/asan_x64.c create mode 100644 frida_mode/src/asan/asan_x86.c create mode 100644 frida_mode/src/ctx/ctx_x64.c create mode 100644 frida_mode/src/ctx/ctx_x86.c create mode 100644 frida_mode/test/cmplog/cmplog.c create mode 100644 frida_mode/test/fasan/GNUmakefile create mode 100644 frida_mode/test/fasan/Makefile create mode 100644 frida_mode/test/fasan/test.c create mode 100644 frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c (limited to 'docs') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5f3429e..35051a20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - name: update run: sudo apt-get update && sudo apt-get upgrade -y - name: install packages - run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools + run: sudo apt-get install -y -m -f --install-suggests build-essential git libtool libtool-bin automake bison libglib2.0-0 clang llvm-dev libc++-dev findutils libcmocka-dev python3-dev python3-setuptools ninja-build - name: compiler installed run: gcc -v ; echo ; clang -v - name: install gcc plugin diff --git a/README.md b/README.md index c16216bf..5d5510d2 100644 --- a/README.md +++ b/README.md @@ -90,16 +90,17 @@ behaviours and defaults: | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| - | NeverZero | x86[_64]| x(1) | x | | x | x | - | Persistent Mode | | x | x | x | x86[_64]/arm[64] | x | + | NeverZero | x86[_64]| x(1) | x | x | x | x | + | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | x | x86[_64]/arm[64] | | + | CmpLog | | x | | x86[_64] | x86[_64]/arm[64] | | | Selective Instrumentation| | x | x | x | x | | | Non-Colliding Coverage | | x(4) | | | (x)(5) | | | Ngram prev_loc Coverage | | x(6) | | | | | | Context Coverage | | x(6) | | | | | | Auto Dictionary | | x(7) | | | | | | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | + | Shared Memory Testcases | | x | x | x | x | x | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin diff --git a/afl-cmin b/afl-cmin index 3f3a7517..adcbb221 100755 --- a/afl-cmin +++ b/afl-cmin @@ -123,6 +123,8 @@ function usage() { "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ +"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ + "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index ceb02bb9..1114a834 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! @@ -28,9 +29,12 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after + no new paths have been found for n seconds - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD @@ -48,6 +52,7 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/INSTALL.md b/docs/INSTALL.md index e3c06c9d..80d452f7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -103,6 +103,41 @@ The llvm instrumentation requires a fully-operational installation of clang. The comes with Xcode is missing some of the essential headers and helper tools. See README.llvm.md for advice on how to build the compiler from scratch. +MacOS X supports SYSV shared memory used by AFL's instrumentation, but the +default settings aren't usable with AFL++. The default settings on 10.14 seem +to be: + +```bash +$ ipcs -M +IPC status from as of XXX +shminfo: + shmmax: 4194304 (max shared memory segment size) + shmmin: 1 (min shared memory segment size) + shmmni: 32 (max number of shared memory identifiers) + shmseg: 8 (max shared memory segments per process) + shmall: 1024 (max amount of shared memory in pages) +``` + +To temporarily change your settings to something minimally usable with AFL++, +run these commands as root: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmall=4096 +``` + +If you're running more than one instance of AFL you likely want to make `shmall` +bigger and increase `shmseg` as well: + +```bash +sysctl kern.sysv.shmmax=8388608 +sysctl kern.sysv.shmseg=48 +sysctl kern.sysv.shmall=98304 +``` + +See http://www.spy-hill.com/help/apple/SharedMemory.html for documentation for +these settings and how to make them permanent. + ## 4. Linux or *BSD on non-x86 systems Standard build will fail on non-x86 systems, but you should be able to diff --git a/docs/env_variables.md b/docs/env_variables.md index 8879db72..c3efa0c0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -285,8 +285,8 @@ checks or alter some of the more exotic semantics of the tool: convenient for some types of automated jobs. - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were - found within a specified period of time. May be convenient for some - types of automated jobs. + found within a specified period of time (in seconds). May be convenient + for some types of automated jobs. - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. @@ -567,6 +567,9 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. + - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. + This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting. + ## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index a15f5c32..bc77a451 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -19,11 +19,13 @@ RT_CFLAGS:=-Wno-unused-parameter \ -Wno-sign-compare \ -Wno-unused-function \ -Wno-unused-result \ + -Wno-int-to-pointer-cast \ LDFLAGS+=-shared \ -lpthread \ -lresolv \ -ldl \ + -z noexecstack \ ifdef DEBUG CFLAGS+=-Werror \ @@ -38,6 +40,8 @@ FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded +ifndef ARCH + ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" ARCH:=arm64 @@ -46,6 +50,7 @@ endif ifeq "$(ARCH)" "i686" ARCH:=x86 endif +endif ifeq "$(shell uname)" "Darwin" OS:=macos @@ -83,13 +88,16 @@ FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME) AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o -.PHONY: all clean format $(FRIDA_GUM) +.PHONY: all 32 clean format $(FRIDA_GUM) ############################## ALL ############################################# all: $(FRIDA_TRACE) make -C $(ROOT) +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $(BUILD_DIR) @@ -161,11 +169,11 @@ $(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $( $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR) $(CC) \ - -o $@ \ $(OBJS) \ $(GUM_DEVIT_LIBRARY) \ $(AFL_COMPILER_RT_OBJ) \ $(LDFLAGS) \ + -o $@ \ cp -v $(FRIDA_TRACE) $(ROOT) diff --git a/frida_mode/Makefile b/frida_mode/Makefile index b6d64bff..6cd1a64e 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean diff --git a/frida_mode/README.md b/frida_mode/README.md index 9f574a4c..ecce0bfd 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -18,19 +18,19 @@ As FRIDA mode is new, it is missing a lot of features. The design is such that i should be possible to add these features in a similar manner to QEMU mode and perhaps leverage some of its design and implementation. - | Feature/Instrumentation | frida-mode | Notes | - | -------------------------|:----------:|:---------------------------------------:| - | NeverZero | x | | - | Persistent Mode | x | (x64 only)(Only on function boundaries) | - | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | - | CMPLOG | x | (x64 only) | - | Selective Instrumentation| x | | - | Non-Colliding Coverage | - | | - | Ngram prev_loc Coverage | - | | - | Context Coverage | - | | - | Auto Dictionary | - | | - | Snapshot LKM Support | - | | - | In-Memory Test Cases | x | (x64 only) | + | Feature/Instrumentation | frida-mode | Notes | + | -------------------------|:----------:|:--------------------------------------------:| + | NeverZero | x | | + | Persistent Mode | x | (x86/x64 only)(Only on function boundaries) | + | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | + | CMPLOG | x | (x86/x64 only) | + | Selective Instrumentation| x | | + | Non-Colliding Coverage | - | (Not possible in binary-only instrumentation | + | Ngram prev_loc Coverage | - | | + | Context Coverage | - | | + | Auto Dictionary | - | | + | Snapshot LKM Support | - | | + | In-Memory Test Cases | x | (x86/x64 only) | ## Compatibility Currently FRIDA mode supports Linux and macOS targets on both x86/x64 @@ -43,11 +43,17 @@ system does not support cross compilation. ## Getting Started -To build everything run `make`. +To build everything run `make`. To build for x86 run `make 32`. Note that in +x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However, +the shared library for frida_mode must be since it is injected into the target +process. Various tests can be found in subfolders within the `test/` directory. To use these, first run `make` to build any dependencies. Then run `make qemu` or -`make frida` to run on either QEMU of FRIDA mode respectively. +`make frida` to run on either QEMU of FRIDA mode respectively. To run frida +tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between +architectures it may be necessary to run `make clean` first for a given build +target to remove previously generated binaries for a different architecture. ## Usage @@ -130,9 +136,47 @@ them and they be inherited by the next child on fork. * `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. +## FASAN - Frida Address Sanitizer Mode +Frida mode also supports FASAN. The design of this is actually quite simple and +very similar to that used when instrumenting applications compiled from source. + +### Address Sanitizer Basics + +When Address Sanitizer is used to instrument programs built from source, the +compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer +dynamic shared object (DSO). This shared object contains the main logic for Address +Sanitizer, including setting and managing up the shadow memory. It also provides +replacement implementations for a number of functions in standard libraries. + +These replacements include things like `malloc` and `free` which allows for those +allocations to be marked in the shadow memory, but also a number of other fuctions. +Consider `memcpy` for example, this is instrumented to validate the paramters +(test the source and destination buffers against the shadow memory. This is much +easier than instrumenting those standard libraries since, first it would require +you to re-compile them and secondly it would mean that the instrumentation would +be applied at a more expensive granular level. Lastly, load-widening (typically +found in highy optimized code) can also make this instrumentation more difficult. + +Since the DSO is loaded before all of the standard libraries (in fact it insists +on being first), the dynamic loader will use it to resolve imports from other +modules which depend on it. + +### FASAN Implementation + +FASAN takes a similar approach. It requires the user to add the Address Sanitizer +DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target. +Again, it must be first in the list. This means that it is not necessary to +instrument the standard libraries to detect when an application has provided an +incorrect argument to `memcpy` for example. This avoids issues with load-widening +and should also mean a huge improvement in performance. + +FASAN then adds instrumentation for any instrucutions which use memory operands and +then calls into the `__asan_loadN` and `__asan_storeN` functions provided by the DSO +to validate memory accesses against the shadow memory. + ## TODO -The next features to be added are x86 support, integration with FuzzBench and -support for ASAN. The intention is to achieve feature parity with QEMU mode in -due course. Contributions are welcome, but please get in touch to ensure that -efforts are deconflicted. +The next features to be added are Aarch64 and Aarch32 support as well as looking at +potential performance improvements. The intention is to achieve feature parity with +QEMU mode in due course. Contributions are welcome, but please get in touch to +ensure that efforts are deconflicted. diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h new file mode 100644 index 00000000..7a8726e0 --- /dev/null +++ b/frida_mode/include/asan.h @@ -0,0 +1,13 @@ +#ifndef _ASAN_H +#define _ASAN_H + +#include "frida-gum.h" + +extern gboolean asan_initialized; + +void asan_init(void); +void asan_arch_init(void); +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +#endif + diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h new file mode 100644 index 00000000..cbcc892a --- /dev/null +++ b/frida_mode/include/ctx.h @@ -0,0 +1,11 @@ +#ifndef _CTX_H +#define _CTX_H + +#include "frida-gum.h" + +#if defined(__x86_64__) || defined(__i386__) +gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg); +#endif + +#endif + diff --git a/frida_mode/include/frida_cmplog.h b/frida_mode/include/frida_cmplog.h index 28864c0e..b620a472 100644 --- a/frida_mode/include/frida_cmplog.h +++ b/frida_mode/include/frida_cmplog.h @@ -8,7 +8,7 @@ void cmplog_init(void); /* Functions to be implemented by the different architectures */ void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator); -gboolean cmplog_is_readable(void *addr, size_t size); +gboolean cmplog_is_readable(guint64 addr, size_t size); #endif diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c new file mode 100644 index 00000000..f78f690c --- /dev/null +++ b/frida_mode/src/asan/asan.c @@ -0,0 +1,24 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" + +gboolean asan_initialized = FALSE; + +void asan_init(void) { + + if (getenv("AFL_USE_FASAN") != NULL) { + + OKF("Frida ASAN mode enabled"); + asan_arch_init(); + asan_initialized = TRUE; + + } else { + + OKF("Frida ASAN mode disabled"); + + } + +} + diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c new file mode 100644 index 00000000..79475ced --- /dev/null +++ b/frida_mode/src/asan/asan_arm.c @@ -0,0 +1,28 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__arm__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +void asan_arch_init(void) { + + FATAL("ASAN mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c new file mode 100644 index 00000000..6262ee18 --- /dev/null +++ b/frida_mode/src/asan/asan_arm64.c @@ -0,0 +1,28 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__aarch64__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +void asan_arch_init(void) { + + FATAL("ASAN mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c new file mode 100644 index 00000000..a2eabe3c --- /dev/null +++ b/frida_mode/src/asan/asan_x64.c @@ -0,0 +1,93 @@ +#include +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +#if defined(__x86_64__) + +typedef void (*asan_loadN_t)(uint64_t address, uint8_t size); +typedef void (*asan_storeN_t)(uint64_t address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + gsize base = 0; + gsize index = 0; + gsize address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c new file mode 100644 index 00000000..8490b490 --- /dev/null +++ b/frida_mode/src/asan/asan_x86.c @@ -0,0 +1,93 @@ +#include +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +#if defined(__i386__) + +typedef void (*asan_loadN_t)(gsize address, uint8_t size); +typedef void (*asan_storeN_t)(gsize address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + gsize base = 0; + gsize index = 0; + gsize address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 3fab1951..7b11c350 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -53,7 +53,7 @@ static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, } -gboolean cmplog_is_readable(void *addr, size_t size) { +gboolean cmplog_is_readable(guint64 addr, size_t size) { if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized"); @@ -65,9 +65,9 @@ gboolean cmplog_is_readable(void *addr, size_t size) { * is lower than this. This should avoid some overhead when functions are * called where one of the parameters is a size, or a some other small value. */ - if (GPOINTER_TO_SIZE(addr) < DEFAULT_MMAP_MIN_ADDR) { return false; } + if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; } - GumAddress inner_base = GUM_ADDRESS(addr); + GumAddress inner_base = addr; GumAddress inner_limit = inner_base + size; for (guint i = 0; i < cmplog_ranges->len; i++) { diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c index 9bf09ad5..9f56c32a 100644 --- a/frida_mode/src/cmplog/cmplog_x64.c +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -3,46 +3,12 @@ #include "debug.h" #include "cmplog.h" +#include "ctx.h" #include "frida_cmplog.h" #include "util.h" #if defined(__x86_64__) - #define X86_REG_8L(LABEL, REG) \ - case LABEL: { \ - \ - return REG & GUM_INT8_MASK; \ - \ - } - - #define X86_REG_8H(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK) >> 8; \ - \ - } - - #define X86_REG_16(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK); \ - \ - } - - #define X86_REG_32(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT32_MASK); \ - \ - } - - #define X86_REG_64(LABEL, REG) \ - case LABEL: { \ - \ - return (REG); \ - \ - } - typedef struct { x86_op_type type; @@ -65,123 +31,81 @@ typedef struct { } cmplog_pair_ctx_t; -static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) { - - switch (reg) { - - X86_REG_8L(X86_REG_AL, ctx->rax) - X86_REG_8L(X86_REG_BL, ctx->rbx) - X86_REG_8L(X86_REG_CL, ctx->rcx) - X86_REG_8L(X86_REG_DL, ctx->rdx) - X86_REG_8L(X86_REG_BPL, ctx->rbp) - X86_REG_8L(X86_REG_SIL, ctx->rsi) - X86_REG_8L(X86_REG_DIL, ctx->rdi) - - X86_REG_8H(X86_REG_AH, ctx->rax) - X86_REG_8H(X86_REG_BH, ctx->rbx) - X86_REG_8H(X86_REG_CH, ctx->rcx) - X86_REG_8H(X86_REG_DH, ctx->rdx) - - X86_REG_16(X86_REG_AX, ctx->rax) - X86_REG_16(X86_REG_BX, ctx->rbx) - X86_REG_16(X86_REG_CX, ctx->rcx) - X86_REG_16(X86_REG_DX, ctx->rdx) - X86_REG_16(X86_REG_DI, ctx->rdi) - X86_REG_16(X86_REG_SI, ctx->rsi) - X86_REG_16(X86_REG_BP, ctx->rbp) - - X86_REG_32(X86_REG_EAX, ctx->rax) - X86_REG_32(X86_REG_ECX, ctx->rcx) - X86_REG_32(X86_REG_EDX, ctx->rdx) - X86_REG_32(X86_REG_EBX, ctx->rbx) - X86_REG_32(X86_REG_ESP, ctx->rsp) - X86_REG_32(X86_REG_EBP, ctx->rbp) - X86_REG_32(X86_REG_ESI, ctx->rsi) - X86_REG_32(X86_REG_EDI, ctx->rdi) - X86_REG_32(X86_REG_R8D, ctx->r8) - X86_REG_32(X86_REG_R9D, ctx->r9) - X86_REG_32(X86_REG_R10D, ctx->r10) - X86_REG_32(X86_REG_R11D, ctx->r11) - X86_REG_32(X86_REG_R12D, ctx->r12) - X86_REG_32(X86_REG_R13D, ctx->r13) - X86_REG_32(X86_REG_R14D, ctx->r14) - X86_REG_32(X86_REG_R15D, ctx->r15) - X86_REG_32(X86_REG_EIP, ctx->rip) - - X86_REG_64(X86_REG_RAX, ctx->rax) - X86_REG_64(X86_REG_RCX, ctx->rcx) - X86_REG_64(X86_REG_RDX, ctx->rdx) - X86_REG_64(X86_REG_RBX, ctx->rbx) - X86_REG_64(X86_REG_RSP, ctx->rsp) - X86_REG_64(X86_REG_RBP, ctx->rbp) - X86_REG_64(X86_REG_RSI, ctx->rsi) - X86_REG_64(X86_REG_RDI, ctx->rdi) - X86_REG_64(X86_REG_R8, ctx->r8) - X86_REG_64(X86_REG_R9, ctx->r9) - X86_REG_64(X86_REG_R10, ctx->r10) - X86_REG_64(X86_REG_R11, ctx->r11) - X86_REG_64(X86_REG_R12, ctx->r12) - X86_REG_64(X86_REG_R13, ctx->r13) - X86_REG_64(X86_REG_R14, ctx->r14) - X86_REG_64(X86_REG_R15, ctx->r15) - X86_REG_64(X86_REG_RIP, ctx->rip) - - default: - FATAL("Failed to read register: %d", reg); - return 0; +static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size, + x86_op_mem *mem, gsize *val) { - } + gsize base = 0; + gsize index = 0; + gsize address; -} + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); -static guint64 cmplog_read_mem(GumX64CpuContext *ctx, x86_op_mem *mem) { + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); - guint64 base = 0; - guint64 index = 0; - guint64 address; + address = base + (index * mem->scale) + mem->disp; - if (mem->base != X86_REG_INVALID) base = cmplog_read_reg(ctx, mem->base); + if (!cmplog_is_readable(address, size)) { return FALSE; } + + switch (size) { + + case 1: + *val = *((guint8 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 2: + *val = *((guint16 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 4: + *val = *((guint32 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 8: + *val = *((guint64 *)GSIZE_TO_POINTER(address)); + return TRUE; + default: + FATAL("Invalid operand size: %d\n", size); - if (mem->index != X86_REG_INVALID) index = cmplog_read_reg(ctx, mem->index); + } - address = base + (index * mem->scale) + mem->disp; - return address; + return FALSE; } -static guint64 cmplog_get_operand_value(GumCpuContext *context, - cmplog_ctx_t * ctx) { +static gboolean cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t *ctx, gsize *val) { switch (ctx->type) { case X86_OP_REG: - return cmplog_read_reg(context, ctx->reg); + *val = ctx_read_reg(context, ctx->reg); + return TRUE; case X86_OP_IMM: - return ctx->imm; + *val = ctx->imm; + return TRUE; case X86_OP_MEM: - return cmplog_read_mem(context, &ctx->mem); + return cmplog_read_mem(context, ctx->size, &ctx->mem, val); default: FATAL("Invalid operand type: %d\n", ctx->type); } + return FALSE; + } static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { UNUSED_PARAMETER(user_data); - guint64 address = cmplog_read_reg(context, X86_REG_RIP); - guint64 rdi = cmplog_read_reg(context, X86_REG_RDI); - guint64 rsi = cmplog_read_reg(context, X86_REG_RSI); + gsize address = ctx_read_reg(context, X86_REG_RIP); + gsize rdi = ctx_read_reg(context, X86_REG_RDI); + gsize rsi = ctx_read_reg(context, X86_REG_RSI); if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return; + if (!cmplog_is_readable(rdi, 32) || !cmplog_is_readable(rsi, 32)) return; + void *ptr1 = GSIZE_TO_POINTER(rdi); void *ptr2 = GSIZE_TO_POINTER(rsi); - if (!cmplog_is_readable(ptr1, 32) || !cmplog_is_readable(ptr2, 32)) return; - uintptr_t k = address; k = (k >> 4) ^ (k << 8); @@ -245,10 +169,10 @@ static void cmplog_instrument_call(const cs_insn * instr, } -static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, - guint64 operand2, uint8_t size) { +static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, + gsize operand2, uint8_t size) { - guint64 address = cmplog_read_reg(context, X86_REG_RIP); + gsize address = ctx_read_reg(context, X86_REG_RIP); register uintptr_t k = (uintptr_t)address; @@ -271,11 +195,13 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + gsize operand1; + gsize operand2; if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); - guint64 operand1 = cmplog_get_operand_value(context, &ctx->operand1); - guint64 operand2 = cmplog_get_operand_value(context, &ctx->operand2); + if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } + if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); diff --git a/frida_mode/src/cmplog/cmplog_x86.c b/frida_mode/src/cmplog/cmplog_x86.c index 2401180c..a27df0af 100644 --- a/frida_mode/src/cmplog/cmplog_x86.c +++ b/frida_mode/src/cmplog/cmplog_x86.c @@ -1,17 +1,275 @@ #include "frida-gum.h" #include "debug.h" +#include "cmplog.h" +#include "ctx.h" #include "frida_cmplog.h" #include "util.h" #if defined(__i386__) + +typedef struct { + + x86_op_type type; + uint8_t size; + + union { + + x86_op_mem mem; + x86_reg reg; + int64_t imm; + + }; + +} cmplog_ctx_t; + +typedef struct { + + cmplog_ctx_t operand1; + cmplog_ctx_t operand2; + +} cmplog_pair_ctx_t; + +static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size, + x86_op_mem *mem, gsize *val) { + + gsize base = 0; + gsize index = 0; + gsize address; + + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); + + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); + + address = base + (index * mem->scale) + mem->disp; + + if (!cmplog_is_readable(address, size)) { return FALSE; } + + switch (size) { + + case 1: + *val = *((guint8 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 2: + *val = *((guint16 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 4: + *val = *((guint32 *)GSIZE_TO_POINTER(address)); + return TRUE; + default: + FATAL("Invalid operand size: %d\n", size); + + } + + return FALSE; + +} + +static gboolean cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t *ctx, gsize *val) { + + switch (ctx->type) { + + case X86_OP_REG: + *val = ctx_read_reg(context, ctx->reg); + return TRUE; + case X86_OP_IMM: + *val = ctx->imm; + return TRUE; + case X86_OP_MEM: + return cmplog_read_mem(context, ctx->size, &ctx->mem, val); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + + return FALSE; + +} + +static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + gsize address = ctx_read_reg(context, X86_REG_EIP); + gsize *esp = (gsize *)ctx_read_reg(context, X86_REG_ESP); + + if (!cmplog_is_readable(GPOINTER_TO_SIZE(esp), 12)) return; + + /* + * This callout is place immediately before the call instruction, and hence + * the return address is not yet pushed on the top of the stack. + */ + gsize arg1 = esp[0]; + gsize arg2 = esp[1]; + + if (((G_MAXULONG - arg1) < 32) || ((G_MAXULONG - arg2) < 32)) return; + + if (!cmplog_is_readable(arg1, 32) || !cmplog_is_readable(arg2, 32)) return; + + void *ptr1 = GSIZE_TO_POINTER(arg1); + void *ptr2 = GSIZE_TO_POINTER(arg2); + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx, + cs_x86_op * operand) { + + ctx->type = operand->type; + ctx->size = operand->size; + switch (operand->type) { + + case X86_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(x86_reg)); + break; + case X86_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case X86_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(x86_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void cmplog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand; + + if (instr->id != X86_INS_CALL) return; + + if (x86.op_count != 1) return; + + operand = &x86.operands[0]; + + if (operand->type == X86_OP_INVALID) return; + if (operand->type == X86_OP_MEM && operand->mem.segment != X86_REG_INVALID) + return; + + gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL); + +} + +static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, + gsize operand2, uint8_t size) { + + gsize address = ctx_read_reg(context, X86_REG_EIP); + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { + + cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + gsize operand1; + gsize operand2; + + if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); + + if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } + if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } + + cmplog_handle_cmp_sub(context, operand1, operand2, ctx->operand1.size); + +} + +static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_x86_op * operand1, + cs_x86_op *operand2) { + + cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t)); + if (ctx == NULL) return; + + cmplog_instrument_put_operand(&ctx->operand1, operand1); + cmplog_instrument_put_operand(&ctx->operand2, operand2); + + gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx, + g_free); + +} + +static void cmplog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_x86 x86 = instr->detail->x86; + cs_x86_op *operand1; + cs_x86_op *operand2; + + switch (instr->id) { + + case X86_INS_CMP: + case X86_INS_SUB: + break; + default: + return; + + } + + if (x86.op_count != 2) return; + + operand1 = &x86.operands[0]; + operand2 = &x86.operands[1]; + + if (operand1->type == X86_OP_INVALID) return; + if (operand2->type == X86_OP_INVALID) return; + + if ((operand1->type == X86_OP_MEM) && + (operand1->mem.segment != X86_REG_INVALID)) + return; + + if ((operand2->type == X86_OP_MEM) && + (operand2->mem.segment != X86_REG_INVALID)) + return; + + cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); + +} + void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(iterator); - if (__afl_cmp_map == NULL) { return; } - FATAL("CMPLOG mode not supported on this architecture"); + if (__afl_cmp_map == NULL) return; + + cmplog_instrument_call(instr, iterator); + cmplog_instrument_cmp_sub(instr, iterator); } diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c new file mode 100644 index 00000000..c5900533 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x64.c @@ -0,0 +1,114 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c new file mode 100644 index 00000000..45308272 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x86.c @@ -0,0 +1,81 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__i386__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + +gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->eax) + X86_REG_8L(X86_REG_BL, ctx->ebx) + X86_REG_8L(X86_REG_CL, ctx->ecx) + X86_REG_8L(X86_REG_DL, ctx->edx) + X86_REG_8L(X86_REG_BPL, ctx->ebp) + X86_REG_8L(X86_REG_SIL, ctx->esi) + X86_REG_8L(X86_REG_DIL, ctx->edi) + + X86_REG_8H(X86_REG_AH, ctx->eax) + X86_REG_8H(X86_REG_BH, ctx->ebx) + X86_REG_8H(X86_REG_CH, ctx->ecx) + X86_REG_8H(X86_REG_DH, ctx->edx) + + X86_REG_16(X86_REG_AX, ctx->eax) + X86_REG_16(X86_REG_BX, ctx->ebx) + X86_REG_16(X86_REG_CX, ctx->ecx) + X86_REG_16(X86_REG_DX, ctx->edx) + X86_REG_16(X86_REG_DI, ctx->edi) + X86_REG_16(X86_REG_SI, ctx->esi) + X86_REG_16(X86_REG_BP, ctx->ebp) + + X86_REG_32(X86_REG_EAX, ctx->eax) + X86_REG_32(X86_REG_ECX, ctx->ecx) + X86_REG_32(X86_REG_EDX, ctx->edx) + X86_REG_32(X86_REG_EBX, ctx->ebx) + X86_REG_32(X86_REG_ESP, ctx->esp) + X86_REG_32(X86_REG_EBP, ctx->ebp) + X86_REG_32(X86_REG_ESI, ctx->esi) + X86_REG_32(X86_REG_EDI, ctx->edi) + X86_REG_32(X86_REG_EIP, ctx->eip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 971f80c0..67eadc3f 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -5,6 +5,7 @@ #include "config.h" #include "debug.h" +#include "asan.h" #include "entry.h" #include "frida_cmplog.h" #include "instrument.h" @@ -33,7 +34,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, */ static char buffer[200]; int len; - guint64 current_pc = (guint64)user_data; + GumAddress current_pc = GUM_ADDRESS(user_data); uint8_t * cursor; uint64_t value; if (unlikely(tracing)) { @@ -85,8 +86,8 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (begin) { - prefetch_write((void *)instr->address); - if (!range_is_excluded((void *)instr->address)) { + prefetch_write(GSIZE_TO_POINTER(instr->address)); + if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) { if (optimize) { @@ -94,8 +95,8 @@ static void instr_basic_block(GumStalkerIterator *iterator, } else { - gum_stalker_iterator_put_callout(iterator, on_basic_block, - (gpointer)instr->address, NULL); + gum_stalker_iterator_put_callout( + iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL); } @@ -105,8 +106,9 @@ static void instr_basic_block(GumStalkerIterator *iterator, } - if (!range_is_excluded((void *)instr->address)) { + if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) { + asan_instrument(instr, iterator); cmplog_instrument(instr, iterator); } @@ -142,6 +144,7 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + asan_init(); cmplog_init(); } diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index c2d720a7..1a3c40bb 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -3,6 +3,7 @@ #include "debug.h" #include "instrument.h" +#include "util.h" #if defined(__arm__) @@ -15,6 +16,8 @@ gboolean instrument_is_coverage_optimize_supported(void) { void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output) { + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); FATAL("Optimized coverage not supported on this architecture"); } diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 5b8cbbba..585bb5b8 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -3,19 +3,81 @@ #include "debug.h" #include "instrument.h" +#include "util.h" #if defined(__i386__) +static GumAddress current_log_impl = GUM_ADDRESS(0); + +static void instrument_coverage_function(GumX86Writer *cw) { + + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_ECX); + gum_x86_writer_put_push_reg(cw, GUM_REG_EDX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, + GUM_ADDRESS(&previous_pc)); + gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_EDX, GUM_REG_ECX); + gum_x86_writer_put_xor_reg_reg(cw, GUM_REG_EDX, GUM_REG_EDI); + + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EDX, GUM_ADDRESS(__afl_area_ptr)); + + /* add byte ptr [edx], 1 */ + uint8_t add_byte_ptr_edx_1[] = {0x80, 0x02, 0x01}; + gum_x86_writer_put_bytes(cw, add_byte_ptr_edx_1, sizeof(add_byte_ptr_edx_1)); + + /* adc byte ptr [edx], 0 */ + uint8_t adc_byte_ptr_edx_0[] = {0x80, 0x12, 0x00}; + gum_x86_writer_put_bytes(cw, adc_byte_ptr_edx_0, sizeof(adc_byte_ptr_edx_0)); + + gum_x86_writer_put_shr_reg_u8(cw, GUM_REG_EDI, 1); + gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_ECX, GUM_REG_EDI); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_EDX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_ECX); + gum_x86_writer_put_popfx(cw); + gum_x86_writer_put_ret(cw); + +} + gboolean instrument_is_coverage_optimize_supported(void) { - return false; + return true; } void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output) { - FATAL("Optimized coverage not supported on this architecture"); + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); + + guint64 current_pc = instr->address; + guint64 area_offset = (current_pc >> 4) ^ (current_pc << 8); + area_offset &= MAP_SIZE - 1; + GumX86Writer *cw = output->writer.x86; + + if (current_log_impl == 0 || + !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || + !gum_x86_writer_can_branch_directly_between(cw->pc + 128, + current_log_impl)) { + + gconstpointer after_log_impl = cw->code + 1; + + gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + + current_log_impl = cw->pc; + instrument_coverage_function(cw); + + gum_x86_writer_put_label(cw, after_log_impl); + + } + + // gum_x86_writer_put_breakpoint(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_EDI); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDI, area_offset); + gum_x86_writer_put_call_address(cw, current_log_impl); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EDI); } diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c index c5045533..13a7d1e7 100644 --- a/frida_mode/src/lib/lib.c +++ b/frida_mode/src/lib/lib.c @@ -90,7 +90,8 @@ static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) { if (!found_preferred_base) { FATAL("Failed to find preferred load address"); } - OKF("Image preferred load address 0x%016lx", preferred_base); + OKF("Image preferred load address 0x%016" G_GSIZE_MODIFIER "x", + preferred_base); shdr = (Elf_Shdr *)((char *)hdr + hdr->e_shoff); shstrtab = &shdr[hdr->e_shstrndx]; @@ -107,15 +108,16 @@ static void lib_read_text_section(lib_details_t *lib_details, Elf_Ehdr *hdr) { if (curr->sh_name == 0) continue; section_name = &shstr[curr->sh_name]; - OKF("Section: %2lu - base: 0x%016lX size: 0x%016lX %s", i, curr->sh_addr, - curr->sh_size, section_name); + OKF("Section: %2" G_GSIZE_MODIFIER "u - base: 0x%016" G_GSIZE_MODIFIER + "X size: 0x%016" G_GSIZE_MODIFIER "X %s", + i, curr->sh_addr, curr->sh_size, section_name); if (memcmp(section_name, text_name, sizeof(text_name)) == 0 && text_base == 0) { text_base = lib_details->base_address + curr->sh_addr - preferred_base; text_limit = text_base + curr->sh_size; - OKF("> text_addr: 0x%016lX", text_base); - OKF("> text_limit: 0x%016lX", text_limit); + OKF("> text_addr: 0x%016" G_GINT64_MODIFIER "X", text_base); + OKF("> text_limit: 0x%016" G_GINT64_MODIFIER "X", text_limit); } @@ -153,7 +155,8 @@ void lib_init(void) { lib_details_t lib_details; gum_process_enumerate_modules(lib_find_exe, &lib_details); - OKF("Executable: 0x%016lx - %s", lib_details.base_address, lib_details.path); + OKF("Executable: 0x%016" G_GINT64_MODIFIER "x - %s", lib_details.base_address, + lib_details.path); lib_get_text_section(&lib_details); } diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index e031dbed..21073cbe 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -75,16 +75,22 @@ static void on_main_os(int argc, char **argv, char **envp) { #endif -static int *on_main(int argc, char **argv, char **envp) { +static void embedded_init() { - void *fork_addr; + static gboolean initialized = false; + if (!initialized) { - on_main_os(argc, argv, envp); + gum_init_embedded(); + initialized = true; - unintercept_self(); + } - stalker_init(); +} + +void afl_frida_start() { + embedded_init(); + stalker_init(); lib_init(); entry_init(); instrument_init(); @@ -92,12 +98,23 @@ static int *on_main(int argc, char **argv, char **envp) { prefetch_init(); ranges_init(); - fork_addr = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); + void *fork_addr = + GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); intercept(fork_addr, on_fork, NULL); stalker_start(); entry_run(); +} + +static int *on_main(int argc, char **argv, char **envp) { + + on_main_os(argc, argv, envp); + + unintercept_self(); + + afl_frida_start(); + return main_fn(argc, argv, envp); } @@ -149,13 +166,7 @@ static void intercept_main(void) { __attribute__((constructor)) static void init(void) { - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - FATAL("Failed to initialize embedded"); - - } + embedded_init(); intercept_main(); diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 9d39c4e9..bd7171b9 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -1,9 +1,9 @@ #include "frida-gum.h" -#include "debug.h" +#include "config.h" +#include "instrument.h" #include "persistent.h" -#include "util.h" #if defined(__i386__) @@ -38,16 +38,239 @@ struct x86_regs { typedef struct x86_regs arch_api_regs; +static arch_api_regs saved_regs = {0}; +static void * saved_return = NULL; + gboolean persistent_is_supported(void) { - return false; + return true; + +} + +static void instrument_persitent_save_regs(GumX86Writer * cw, + struct x86_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + + /* Should be pushing FPU here, but meh */ + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1), + GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2), + GUM_REG_ECX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3), + GUM_REG_EDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4), + GUM_REG_EDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5), + GUM_REG_ESI); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6), + GUM_REG_EBP); + + /* Store RIP */ + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX, + GUM_ADDRESS(persistent_start)); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7), + GUM_REG_EBX); + + /* Store adjusted RSP */ + gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP); + + /* RED_ZONE + Saved flags, RAX */ + gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2)); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8), + GUM_REG_EBX); + + /* Save the flags */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9), + GUM_REG_EBX); + + /* Save the RAX */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0), + GUM_REG_EBX); + + /* Pop the saved values */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8); + +} + +static void instrument_persitent_restore_regs(GumX86Writer * cw, + struct x86_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX, + (0x4 * 2)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX, + (0x4 * 3)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX, + (0x4 * 4)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX, + (0x4 * 5)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX, + (0x4 * 6)); + + /* Don't restore RIP or RSP */ + + /* Restore RBX, RAX & Flags */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, + (0x4 * 1)); + gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); + + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, + (0x4 * 0)); + gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, + (0x4 * 9)); + gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); + + gum_x86_writer_put_popfx(cw); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX); + +} + +static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + + gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x8); + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, 0, GUM_REG_EBX); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); + +} + +static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) { + + GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); + + /* Place holder for ret */ + gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EAX, GUM_REG_EAX, 0); + + gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_ESP, 0x4, GUM_REG_EAX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_ret(cw); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +static void instrument_afl_persistent_loop(GumX86Writer *cw) { + + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); + gum_x86_writer_put_test_reg_reg(cw, GUM_REG_EAX, GUM_REG_EAX); + +} + +static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { + + if (hook == NULL) return; + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, + GUM_ADDRESS(&__afl_fuzz_len)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_ECX, 0); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDX, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EDX, 0); + + /* Base address is 64-bits (hence two zero arguments) */ + gum_x86_writer_put_call_address_with_arguments( + cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 5, GUM_ARG_ADDRESS, + GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS, + GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER, + GUM_REG_ECX); } void persistent_prologue(GumStalkerOutput *output) { - UNUSED_PARAMETER(output); - FATAL("Persistent mode not supported on this architecture"); + /* + * SAVE REGS + * SAVE RET + * POP RET + * loop: + * CALL instrument_afl_persistent_loop + * TEST EAX, EAX + * JZ end: + * call hook (optionally) + * RESTORE REGS + * call original + * jmp loop: + * + * end: + * JMP SAVED RET + * + * original: + * INSTRUMENTED PERSISTENT FUNC + */ + + GumX86Writer *cw = output->writer.x86; + + gconstpointer loop = cw->code + 1; + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* Stash and pop the return value */ + instrument_save_ret(cw, &saved_return); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4)); + + /* loop: */ + gum_x86_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, done, GUM_UNLIKELY); + + /* Optionally call the persistent hook */ + persistent_prologue_hook(cw, &saved_regs); + + instrument_persitent_restore_regs(cw, &saved_regs); + gconstpointer original = cw->code + 1; + /* call original */ + gum_x86_writer_put_call_near_label(cw, original); + /* jmp loop */ + gum_x86_writer_put_jmp_near_label(cw, loop); + + /* done: */ + gum_x86_writer_put_label(cw, done); + + instrument_jump_ret(cw, &saved_return); + + /* original: */ + gum_x86_writer_put_label(cw, original); + + gum_x86_writer_flush(cw); } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index 81973e9c..63f3c529 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -7,6 +7,8 @@ static GumStalker *stalker = NULL; void stalker_init(void) { + if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); } + stalker = gum_stalker_new(); if (stalker == NULL) { FATAL("Failed to initialize stalker"); } diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile index c203fc5e..40de6a09 100644 --- a/frida_mode/test/cmplog/GNUmakefile +++ b/frida_mode/test/cmplog/GNUmakefile @@ -2,8 +2,8 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../../)/ BUILD_DIR:=$(PWD)build/ -TEST_CMPLOG_DIR:=$(ROOT)qemu_mode/libcompcov/ -TEST_CMPLOG_OBJ=$(TEST_CMPLOG_DIR)compcovtest +TEST_CMPLOG_SRC=$(PWD)cmplog.c +TEST_CMPLOG_OBJ=$(BUILD_DIR)compcovtest TEST_BIN:=$(PWD)../../build/test @@ -13,20 +13,14 @@ CMP_LOG_INPUT:=$(TEST_DATA_DIR)in QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -ARCH=$(shell uname -m) -ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000aaaaaaaaa000) -endif +.PHONY: all 32 clean qemu frida format -ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_INST_RANGES=$(shell $(PWD)get_section_addrs.py -f $(TEST_CMPLOG_OBJ) -s .text -b 0x0000555555554000) -endif - -.PHONY: all clean qemu frida - -all: +all: $(TEST_CMPLOG_OBJ) make -C $(ROOT)frida_mode/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -34,33 +28,42 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) mkdir -p $@ $(CMP_LOG_INPUT): | $(TEST_DATA_DIR) - truncate -s 64 $@ + echo -n "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" > $@ -$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_DIR)compcovtest.cc - make -C $(TEST_CMPLOG_DIR) compcovtest +$(TEST_CMPLOG_OBJ): $(TEST_CMPLOG_SRC) | $(BUILD_DIR) + $(CXX) -std=c++11 -g $(CFLAGS) $(LDFLAGS) $< -o $@ qemu: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) $(ROOT)afl-fuzz \ - -D \ -Q \ -i $(TEST_DATA_DIR) \ -o $(QEMU_OUT) \ -c 0 \ -l 3AT \ + -Z \ -- \ $(TEST_CMPLOG_OBJ) @@ frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) - XAFL_FRIDA_INST_RANGES=$(AFL_FRIDA_INST_RANGES) \ $(ROOT)afl-fuzz \ - -D \ -O \ -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ -c 0 \ -l 3AT \ + -Z \ -- \ $(TEST_CMPLOG_OBJ) @@ +debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r $(CMP_LOG_INPUT)' \ + --args $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + clean: - rm -rf $(BUILD_DIR) \ No newline at end of file + rm -rf $(BUILD_DIR) + +format: + cd $(ROOT) && echo $(TEST_CMPLOG_SRC) | xargs -L1 ./.custom-format.py -i diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile index f322d1f5..606b43a5 100644 --- a/frida_mode/test/cmplog/Makefile +++ b/frida_mode/test/cmplog/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -9,4 +13,10 @@ qemu: @gmake qemu frida: - @gmake frida \ No newline at end of file + @gmake frida + +format: + @gmake format + +debug: + @gmake debug diff --git a/frida_mode/test/cmplog/cmplog.c b/frida_mode/test/cmplog/cmplog.c new file mode 100644 index 00000000..99010645 --- /dev/null +++ b/frida_mode/test/cmplog/cmplog.c @@ -0,0 +1,100 @@ +///////////////////////////////////////////////////////////////////////// +// +// Author: Mateusz Jurczyk (mjurczyk@google.com) +// +// Copyright 2019-2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// solution: echo -ne 'The quick brown fox jumps over the lazy +// dog\xbe\xba\xfe\xca\xbe\xba\xfe\xca\xde\xc0\xad\xde\xef\xbe' | ./compcovtest + +#include +#include +#include +#include + +int main(int argc, char **argv) { + + char buffer[44] = {/* zero padding */}; + + FILE *file = stdin; + + if (argc > 1) { + + if ((file = fopen(argv[1], "r")) == NULL) { + + perror(argv[1]); + exit(-1); + + } + + } + + fread(buffer, 1, sizeof(buffer) - 1, file); + + if (memcmp(&buffer[0], "The quick brown fox ", 20) != 0 || + strncmp(&buffer[20], "jumps over ", 11) != 0 || + strcmp(&buffer[31], "the lazy dog") != 0) { + + if (argc > 1) { fclose(file); } + return 1; + + } + +#if defined(__x86_64__) + uint64_t x = 0; + fread(&x, sizeof(x), 1, file); + if (x != 0xCAFEBABECAFEBABE) { + + if (argc > 1) { fclose(file); } + return 2; + + } + +#endif + + uint32_t y = 0; + fread(&y, sizeof(y), 1, file); + + if (y != 0xDEADC0DE) { + + if (argc > 1) { fclose(file); } + return 3; + + } + + uint16_t z = 0; + fread(&z, sizeof(z), 1, file); + + switch (z) { + + case 0xBEEF: + break; + + default: + if (argc > 1) { fclose(file); } + return 4; + + } + + printf("Puzzle solved, congrats!\n"); + abort(); + + if (argc > 1) { fclose(file); } + + return 0; + +} + diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile index 891827eb..c99bcecb 100644 --- a/frida_mode/test/entry_point/GNUmakefile +++ b/frida_mode/test/entry_point/GNUmakefile @@ -12,6 +12,18 @@ FRIDA_OUT:=$(BUILD_DIR)frida-out GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) @@ -21,11 +33,18 @@ ifeq "$(ARCH)" "x86_64" AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) endif +ifeq "$(ARCH)" "x86" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) +endif + .PHONY: all clean qemu frida all: $(TESTINSTBIN) make -C $(ROOT)frida_mode/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -36,7 +55,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< clean: rm -rf $(BUILD_DIR) @@ -58,4 +77,4 @@ frida_entry: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -i $(TESTINSTR_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TESTINSTBIN) @@ \ No newline at end of file + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/entry_point/Makefile b/frida_mode/test/entry_point/Makefile index 3b41b94e..75c57e66 100644 --- a/frida_mode/test/entry_point/Makefile +++ b/frida_mode/test/entry_point/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -9,4 +13,4 @@ frida: @gmake frida frida_entry: - @gmake frida \ No newline at end of file + @gmake frida diff --git a/frida_mode/test/entry_point/testinstr.c b/frida_mode/test/entry_point/testinstr.c index a6c655f9..bd605c52 100644 --- a/frida_mode/test/entry_point/testinstr.c +++ b/frida_mode/test/entry_point/testinstr.c @@ -106,7 +106,9 @@ int run(char *file) { } void slow() { + usleep(100000); + } int main(int argc, char **argv) { diff --git a/frida_mode/test/exe/GNUmakefile b/frida_mode/test/exe/GNUmakefile index c543cca8..86e5a461 100644 --- a/frida_mode/test/exe/GNUmakefile +++ b/frida_mode/test/exe/GNUmakefile @@ -10,11 +10,14 @@ TESTINSTSRC:=$(PWD)testinstr.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -.PHONY: all clean qemu frida +.PHONY: all 32 clean qemu frida all: $(TESTINSTBIN) make -C $(ROOT)frida_mode/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -25,7 +28,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) -o $@ $< -no-pie + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -no-pie clean: rm -rf $(BUILD_DIR) @@ -47,4 +50,4 @@ frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -i $(TESTINSTR_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TESTINSTBIN) @@ \ No newline at end of file + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/exe/Makefile b/frida_mode/test/exe/Makefile index f322d1f5..4bef1ccb 100644 --- a/frida_mode/test/exe/Makefile +++ b/frida_mode/test/exe/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -9,4 +13,4 @@ qemu: @gmake qemu frida: - @gmake frida \ No newline at end of file + @gmake frida diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile new file mode 100644 index 00000000..08b271de --- /dev/null +++ b/frida_mode/test/fasan/GNUmakefile @@ -0,0 +1,159 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)in +FRIDA_OUT:=$(BUILD_DIR)frida-out + +TEST_SRC:=$(PWD)/test.c +TEST_BIN:=$(BUILD_DIR)test + +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -g \ + -fno-omit-frame-pointer \ + -Wno-stringop-overflow \ + +LDFLAGS+=-ldl \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "x86" +LIBASAN_FILE:=libclang_rt.asan-i386.so +endif + +ifeq "$(ARCH)" "x86_64" +LIBASAN_FILE:=libclang_rt.asan-x86_64.so +endif + +ifeq "$(ARCH)" "aarch64" +LIBASAN_FILE:=libclang_rt.asan-aarch64.so +endif + +# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so +# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 + +LLVM_CONFIG ?= llvm-config +ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1" + $(info Found llvm-config: '$(shell which $(LLVM_CONFIG))') +else + $(warning Cannot find llvm-config) +endif + +LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/ +$(info LLVM_BINDIR: $(LLVM_BINDIR)) + +CLANG ?= $(LLVM_BINDIR)clang +ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1" + $(info Found clang: '$(CLANG)') +else + $(warning Cannot find clang) +endif + +CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') +$(info Clang version $(CLANGVER)) + +LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) +$(info LLVM_LIBDIR: $(LLVM_LIBDIR)) + +LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE) + +ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1" + $(info Found Address Sanitizer DSO: '$(LIBASAN)') +else + $(error Error cannot find Address Sanitizer DSO) +endif + + +.PHONY: all 32 clean format frida-noasan frida debug run + +############################## ALL ############################################# + +all: $(TEST_BIN) + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + $(LDFLAGS) \ + -o $@ \ + $< + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# TESTS ############################################ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo -n "TUODATM" > $@ + +frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + + +frida: $(TEST_BIN) $(TEST_DATA_FILE) + AFL_PRELOAD=$(LIBASAN) \ + AFL_USE_FASAN=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + +debug: $(TEST_BIN) $(TEST_DATA_FILE) + gdb \ + --ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \ + --ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \ + --ex 'set environment AFL_USE_FASAN=1' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r < $(TEST_DATA_FILE)' \ + --args $(TEST_BIN) \ + +run: $(TEST_BIN) $(TEST_DATA_FILE) + LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \ + ASAN_OPTIONS=detect_leaks=false \ + AFL_USE_FASAN=1 \ + $(TEST_BIN) < $(TEST_DATA_FILE) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/test/fasan/Makefile b/frida_mode/test/fasan/Makefile new file mode 100644 index 00000000..3b4c71db --- /dev/null +++ b/frida_mode/test/fasan/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida-noasan: + @gmake frida-noasan + +frida: + @gmake frida + +debug: + @gmake debug + +run: + @gmake run diff --git a/frida_mode/test/fasan/test.c b/frida_mode/test/fasan/test.c new file mode 100644 index 00000000..b9a119e6 --- /dev/null +++ b/frida_mode/test/fasan/test.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAMETER(x) (void)(x) + +#define LOG(x) \ + do { \ + \ + char buf[] = x; \ + write(STDOUT_FILENO, buf, sizeof(buf)); \ + \ + } while (false); + +void test(char data) { + + char *buf = malloc(10); + + if (buf == NULL) return; + + switch (data) { + + /* Underflow */ + case 'U': + LOG("Underflow\n"); + buf[-1] = '\0'; + free(buf); + break; + /* Overflow */ + case 'O': + LOG("Overflow\n"); + buf[10] = '\0'; + free(buf); + break; + /* Double free */ + case 'D': + LOG("Double free\n"); + free(buf); + free(buf); + break; + /* Use after free */ + case 'A': + LOG("Use after free\n"); + free(buf); + buf[0] = '\0'; + break; + /* Test Limits (OK) */ + case 'T': + LOG("Test-Limits - No Error\n"); + buf[0] = 'A'; + buf[9] = 'I'; + free(buf); + break; + case 'M': + LOG("Memset too many\n"); + memset(buf, '\0', 11); + free(buf); + break; + default: + LOG("Nop - No Error\n"); + break; + + } + +} + +int main(int argc, char **argv) { + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + + char input = '\0'; + + if (read(STDIN_FILENO, &input, 1) < 0) { + + LOG("Failed to read stdin\n"); + return 1; + + } + + test(input); + + LOG("DONE\n"); + return 0; + +} + diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile index 515728c4..e05bade2 100644 --- a/frida_mode/test/png/GNUmakefile +++ b/frida_mode/test/png/GNUmakefile @@ -35,6 +35,9 @@ FRIDA_OUT:=$(BUILD_DIR)frida-out all: $(TEST_BIN) make -C $(ROOT)frida_mode/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -46,7 +49,7 @@ $(HARNESS_FILE): | $(HARNESS_BUILD_DIR) wget -O $@ $(HARNESS_URL) $(HARNESS_OBJ): $(HARNESS_FILE) - $(CC) -o $@ -c $< + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ -c $< ######### PNGTEST ######## @@ -57,7 +60,7 @@ $(PNGTEST_FILE): | $(PNGTEST_BUILD_DIR) wget -O $@ $(PNGTEST_URL) $(PNGTEST_OBJ): $(PNGTEST_FILE) | $(LIBPNG_DIR) - $(CXX) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< + $(CXX) $(CFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBPNG_DIR) -o $@ -c $< ######### LIBPNG ######## @@ -80,6 +83,8 @@ $(LIBPNG_LIB): $(LIBPNG_MAKEFILE) $(TEST_BIN): $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) $(CXX) \ + $(CFLAGS) \ + $(LDFLAGS) \ -o $@ \ $(HARNESS_OBJ) $(PNGTEST_OBJ) $(LIBPNG_LIB) \ -lz \ diff --git a/frida_mode/test/png/Makefile b/frida_mode/test/png/Makefile index f322d1f5..4bef1ccb 100644 --- a/frida_mode/test/png/Makefile +++ b/frida_mode/test/png/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -9,4 +13,4 @@ qemu: @gmake qemu frida: - @gmake frida \ No newline at end of file + @gmake frida diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile index 531f9bce..ca6f0ff2 100644 --- a/frida_mode/test/png/persistent/GNUmakefile +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -8,6 +8,18 @@ TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) ARCH=$(shell uname -m) @@ -19,11 +31,18 @@ ifeq "$(ARCH)" "x86_64" AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000) endif -.PHONY: all clean qemu qemu_entry frida frida_entry +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x56555000) +endif + +.PHONY: all 32 clean qemu qemu_entry frida frida_entry all: make -C $(ROOT)frida_mode/test/png/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -76,4 +95,4 @@ frida_entry: | $(BUILD_DIR) $(TEST_BIN) @@ clean: - rm -rf $(BUILD_DIR) \ No newline at end of file + rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile index 5fde63c2..cde0cf30 100644 --- a/frida_mode/test/png/persistent/Makefile +++ b/frida_mode/test/png/persistent/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -15,4 +19,4 @@ frida: @gmake frida frida_entry: - @gmake frida_entry \ No newline at end of file + @gmake frida_entry diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py index 6458c212..1c46e010 100755 --- a/frida_mode/test/png/persistent/get_symbol_addr.py +++ b/frida_mode/test/png/persistent/get_symbol_addr.py @@ -33,4 +33,4 @@ def main(): if __name__ == "__main__": ret = main() - exit(ret) \ No newline at end of file + exit(ret) diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile index 4f55fe98..82f08fa4 100644 --- a/frida_mode/test/png/persistent/hook/GNUmakefile +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -2,8 +2,16 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_DIR=$(ROOT)utils/aflpp_driver/ -AFLPP_DRIVER_HOOK_OBJ=$(AFLPP_DRIVER_HOOK_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +CFLAGS+=-O3 \ + -funroll-loops \ + -g \ + -fPIC \ + -funroll-loops \ + +LDFLAGS+=-shared \ TEST_BIN:=$(PWD)../../build/test TEST_DATA_DIR:=../../build/libpng/libpng-1.2.56/contrib/pngsuite/ @@ -12,9 +20,20 @@ AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) +ifndef ARCH ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + ifeq "$(ARCH)" "aarch64" AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) endif @@ -23,6 +42,18 @@ ifeq "$(ARCH)" "x86_64" AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) endif +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug + +all: $(AFLPP_DRIVER_HOOK_OBJ) + make -C $(ROOT)frida_mode/test/png/persistent/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + .PHONY: all clean qemu qemu_entry frida frida_entry all: @@ -37,8 +68,8 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) truncate -s 1M $@ -$(AFLPP_DRIVER_HOOK_OBJ): | $(AFLPP_DRIVER_HOOK_DIR) - make -C $(AFLPP_DRIVER_HOOK_DIR) +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ @@ -93,6 +124,18 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) +debug: + echo $(AFL_FRIDA_PERSISTENT_ADDR) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + clean: rm -rf $(BUILD_DIR) +format: + cd $(ROOT) && echo $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i + diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile index 5fde63c2..983d009e 100644 --- a/frida_mode/test/png/persistent/hook/Makefile +++ b/frida_mode/test/png/persistent/hook/Makefile @@ -2,9 +2,16 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean +format: + @gmake format + qemu: @gmake qemu @@ -15,4 +22,7 @@ frida: @gmake frida frida_entry: - @gmake frida_entry \ No newline at end of file + @gmake frida_entry + +debug: + @gmake debug diff --git a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include +#include + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/testinstr/GNUmakefile b/frida_mode/test/testinstr/GNUmakefile index 4addbad8..a35073ab 100644 --- a/frida_mode/test/testinstr/GNUmakefile +++ b/frida_mode/test/testinstr/GNUmakefile @@ -10,11 +10,14 @@ TESTINSTSRC:=$(PWD)testinstr.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -.PHONY: all clean qemu frida +.PHONY: all 32 clean qemu frida all: $(TESTINSTBIN) make -C $(ROOT)frida_mode/ +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + $(BUILD_DIR): mkdir -p $@ @@ -25,7 +28,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< clean: rm -rf $(BUILD_DIR) @@ -47,4 +50,10 @@ frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -i $(TESTINSTR_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TESTINSTBIN) @@ \ No newline at end of file + $(TESTINSTBIN) @@ + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) diff --git a/frida_mode/test/testinstr/Makefile b/frida_mode/test/testinstr/Makefile index f322d1f5..f843af19 100644 --- a/frida_mode/test/testinstr/Makefile +++ b/frida_mode/test/testinstr/Makefile @@ -2,6 +2,10 @@ all: @echo trying to use GNU make... @gmake all || echo please install GNUmake +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + clean: @gmake clean @@ -9,4 +13,7 @@ qemu: @gmake qemu frida: - @gmake frida \ No newline at end of file + @gmake frida + +debug: + @gmake debug diff --git a/include/envs.h b/include/envs.h index 9175005e..f1314bad 100644 --- a/include/envs.h +++ b/include/envs.h @@ -191,7 +191,9 @@ static char *afl_environment_variables[] = { "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", + "AFL_USE_FASAN", "AFL_USE_QASAN", + "AFL_PRINT_FILENAMES", NULL }; diff --git a/include/forkserver.h b/include/forkserver.h index 48db94c7..2baa6f0a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { bool frida_mode; /* if running in frida mode or not */ + bool frida_asan; /* if running with asan in frida mode */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/qemu_mode/libqasan/hooks.c b/qemu_mode/libqasan/hooks.c index 0e6c3e08..c542521c 100644 --- a/qemu_mode/libqasan/hooks.c +++ b/qemu_mode/libqasan/hooks.c @@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libqasan.h" #include "map_macro.h" +#include +#include -ssize_t (*__lq_libc_write)(int, const void *, size_t); -ssize_t (*__lq_libc_read)(int, void *, size_t); char *(*__lq_libc_fgets)(char *, int, FILE *); int (*__lq_libc_atoi)(const char *); long (*__lq_libc_atol)(const char *); @@ -37,8 +37,6 @@ void __libqasan_init_hooks(void) { __libqasan_init_malloc(); - __lq_libc_write = ASSERT_DLSYM(write); - __lq_libc_read = ASSERT_DLSYM(read); __lq_libc_fgets = ASSERT_DLSYM(fgets); __lq_libc_atoi = ASSERT_DLSYM(atoi); __lq_libc_atol = ASSERT_DLSYM(atol); @@ -52,7 +50,7 @@ ssize_t write(int fd, const void *buf, size_t count) { QASAN_DEBUG("%14p: write(%d, %p, %zu)\n", rtv, fd, buf, count); QASAN_LOAD(buf, count); - ssize_t r = __lq_libc_write(fd, buf, count); + ssize_t r = syscall(SYS_write, fd, buf, count); QASAN_DEBUG("\t\t = %zd\n", r); return r; @@ -65,7 +63,7 @@ ssize_t read(int fd, void *buf, size_t count) { QASAN_DEBUG("%14p: read(%d, %p, %zu)\n", rtv, fd, buf, count); QASAN_STORE(buf, count); - ssize_t r = __lq_libc_read(fd, buf, count); + ssize_t r = syscall(SYS_read, fd, buf, count); QASAN_DEBUG("\t\t = %zd\n", r); return r; diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index 9fc4ef7a..2ac0c861 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -61,9 +61,17 @@ void __libqasan_print_maps(void) { } -/*__attribute__((constructor))*/ void __libqasan_init() { +int __libqasan_is_initialized = 0; + +__attribute__((constructor)) void __libqasan_init() { + + if (__libqasan_is_initialized) return; + __libqasan_is_initialized = 1; __libqasan_init_hooks(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) + __libqasan_hotpatch(); #ifdef DEBUG __qasan_debug = getenv("QASAN_DEBUG") != NULL; @@ -86,7 +94,6 @@ int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv, typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main"); __libqasan_init(); - if (getenv("AFL_INST_LIBS")) __libqasan_hotpatch(); return orig(main, argc, argv, init, fini, rtld_fini, stack_end); diff --git a/src/afl-cc.c b/src/afl-cc.c index 09009334..ff7b5219 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,7 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) +#ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; +#else compiler_mode = GCC; +#endif else if (have_lto) compiler_mode = LTO; else @@ -1596,7 +1601,12 @@ int main(int argc, char **argv, char **envp) { } - if (compiler_mode == CLANG) { instrument_mode = INSTRUMENT_CLANG; } + if (compiler_mode == CLANG) { + + instrument_mode = INSTRUMENT_CLANG; + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a07e78b4..3d472b36 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -451,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered before the dump is complete. */ - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + if (!fsrv->debug) { + + r.rlim_max = r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + } /* Isolate the process and configure standard descriptors. If out_file is specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index cb586111..c43bcc2b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1044,18 +1044,16 @@ void perform_dry_run(afl_state_t *afl) { /* Remove from fuzzing queue but keep for splicing */ - struct queue_entry *p = afl->queue; + if (!q->was_fuzzed) { - if (!p->was_fuzzed) { - - p->was_fuzzed = 1; + q->was_fuzzed = 1; --afl->pending_not_fuzzed; --afl->active_paths; } - p->disabled = 1; - p->perf_score = 0; + q->disabled = 1; + q->perf_score = 0; u32 i = 0; while (unlikely(i < afl->queued_paths && afl->queue_buf[i] && @@ -1294,9 +1292,13 @@ void pivot_inputs(afl_state_t *afl) { if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { - struct queue_entry *s = afl->queue_buf[src_id]; + if (src_id < afl->queued_paths) { + + struct queue_entry *s = afl->queue_buf[src_id]; - if (s) { q->depth = s->depth + 1; } + if (s) { q->depth = s->depth + 1; } + + } if (afl->max_depth < q->depth) { afl->max_depth = q->depth; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4eeb93de..4a3e7f33 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2013,7 +2013,7 @@ havoc_stage: } - if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ @@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 313263f9..4884b942 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -368,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, afl->plot_prev_uh == afl->unique_hangs && afl->plot_prev_md == afl->max_depth && afl->plot_prev_ed == afl->fsrv.total_execs) || - !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { + !afl->queue_cycle || + get_cur_time() - afl->start_time <= 60000))) { return; @@ -393,7 +394,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(afl->fsrv.plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%u\n", - (afl->prev_run_time + get_cur_time() - afl->start_time), + ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000), afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8de3ed6b..5f939115 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -328,11 +328,55 @@ static int stricmp(char const *a, char const *b) { } +static void fasan_check_afl_preload(char *afl_preload) { + + char first_preload[PATH_MAX + 1] = {0}; + char * separator = strchr(afl_preload, ':'); + size_t first_preload_len = PATH_MAX; + char * basename; + char clang_runtime_prefix[] = "libclang_rt.asan-"; + + if (separator != NULL && (separator - afl_preload) < PATH_MAX) { + + first_preload_len = separator - afl_preload; + + } + + strncpy(first_preload, afl_preload, first_preload_len); + + basename = strrchr(first_preload, '/'); + if (basename == NULL) { + + basename = first_preload; + + } else { + + basename = basename + 1; + + } + + if (strncmp(basename, clang_runtime_prefix, + sizeof(clang_runtime_prefix) - 1) != 0) { + + FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD"); + + } + + if (access(first_preload, R_OK) != 0) { + + FATAL("Address Sanitizer DSO not found"); + + } + + OKF("Found ASAN DSO: %s", first_preload); + +} + /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { - s32 opt, i, auto_sync = 0 /*, user_set_cache = 0*/; + s32 opt, auto_sync = 0 /*, user_set_cache = 0*/; u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, map_size = get_map_size(); @@ -785,6 +829,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl->fsrv.frida_mode = 1; + if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; } break; @@ -1369,18 +1414,26 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Injecting %s ...", frida_binary); if (afl_preload) { - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + if (afl->fsrv.frida_asan) { - } else { + OKF("Using Frida Address Sanitizer Mode"); - frida_afl_preload = alloc_printf("%s", frida_binary); + fasan_check_afl_preload(afl_preload); - } + setenv("ASAN_OPTIONS", "detect_leaks=false", 1); - ck_free(frida_binary); + } + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + ck_free(frida_binary); + + setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); - setenv("LD_PRELOAD", frida_afl_preload, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + } } else { @@ -1391,11 +1444,22 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - OKF("Injecting %s ...", frida_binary); - setenv("LD_PRELOAD", frida_binary, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - ck_free(frida_binary); + if (afl->fsrv.frida_asan) { + + OKF("Using Frida Address Sanitizer Mode"); + FATAL( + "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida " + "Address Sanitizer Mode"); + + } else { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + ck_free(frida_binary); + + } } @@ -1770,7 +1834,7 @@ int main(int argc, char **argv_orig, char **envp) { if (extras_dir_cnt) { - for (i = 0; i < extras_dir_cnt; i++) { + for (u8 i = 0; i < extras_dir_cnt; i++) { load_extras(afl, extras_dir[i]); @@ -1922,6 +1986,13 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(seek_to)) { + if (unlikely(seek_to >= afl->queued_paths)) { + + // This should never happen. + FATAL("BUG: seek_to location out of bounds!\n"); + + } + afl->current_entry = seek_to; afl->queue_cur = afl->queue_buf[seek_to]; seek_to = 0; @@ -1940,8 +2011,10 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (unlikely(afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600)) { + if (unlikely(afl->queued_paths == prev_queued + /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >= + 3600 */ + )) { if (afl->use_splicing) { @@ -2059,7 +2132,7 @@ int main(int argc, char **argv_orig, char **envp) { } // we must recalculate the scores of all queue entries - for (i = 0; i < (s32)afl->queued_paths; i++) { + for (u32 i = 0; i < afl->queued_paths; i++) { if (likely(!afl->queue_buf[i]->disabled)) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 946b19cd..9b4d21a5 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -76,17 +76,18 @@ static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; -static u8 quiet_mode, /* Hide non-essential messages? */ +static bool quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1, /* remove shmem? */ + remove_shm = true, /* remove shmem? */ collect_coverage, /* collect coverage */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ - debug; /* debug mode */ + debug, /* debug mode */ + print_filenames; /* print the current filename */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -320,11 +321,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -335,11 +336,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { - child_crashed = 1; + child_crashed = true; } else { - child_crashed = 0; + child_crashed = false; } @@ -375,6 +376,13 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { + if (print_filenames) { + + SAYF("Processing %s\n", in_file); + fflush(stdout); + + } + struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -386,7 +394,18 @@ static u32 read_file(u8 *in_file) { } - in_len = st.st_size; + if (st.st_size > MAX_FILE) { + + WARNF("Input file '%s' is too large, only reading %u bytes.", in_file, + MAX_FILE); + in_len = MAX_FILE; + + } else { + + in_len = st.st_size; + + } + in_data = ck_alloc_nozero(in_len); ck_read(fd, in_data, in_len, in_file); @@ -504,11 +523,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -518,7 +537,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) { - child_crashed = 1; + child_crashed = true; } @@ -548,7 +567,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static void handle_stop_sig(int sig) { (void)sig; - stop_soon = 1; + stop_soon = true; afl_fsrv_killall(); } @@ -731,6 +750,8 @@ static void usage(u8 *argv0) { "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " + "printed to stdout\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -744,14 +765,17 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt, i; + bool mem_limit_given = false, timeout_given = false, unicorn_mode = false, + use_wine = false; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); afl_forkserver_t fsrv_var = {0}; - if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_DEBUG")) { debug = true; } + if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; } + fsrv = &fsrv_var; afl_fsrv_init(fsrv); map_size = get_map_size(); @@ -759,19 +783,19 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } + if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { case 's': - no_classify = 1; + no_classify = true; break; case 'C': - collect_coverage = 1; - quiet_mode = 1; + collect_coverage = true; + quiet_mode = true; break; case 'i': @@ -790,7 +814,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 suffix = 'M'; if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; + mem_limit_given = true; if (!optarg) { FATAL("Wrong usage of -m"); } @@ -851,7 +875,7 @@ int main(int argc, char **argv_orig, char **envp) { case 't': if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; + timeout_given = true; if (!optarg) { FATAL("Wrong usage of -t"); } @@ -873,12 +897,12 @@ int main(int argc, char **argv_orig, char **envp) { if (edges_only) { FATAL("Multiple -e options not supported"); } if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); } - edges_only = 1; + edges_only = true; break; case 'q': - quiet_mode = 1; + quiet_mode = true; break; case 'Z': @@ -886,8 +910,8 @@ int main(int argc, char **argv_orig, char **envp) { /* This is an undocumented option to write data in the syntax expected by afl-cmin. Nobody else should have any use for this. */ - cmin_mode = 1; - quiet_mode = 1; + cmin_mode = true; + quiet_mode = true; break; case 'A': @@ -899,7 +923,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } - fsrv->frida_mode = 1; + fsrv->frida_mode = true; break; @@ -907,21 +931,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - fsrv->qemu_mode = 1; + fsrv->qemu_mode = true; break; case 'U': if (unicorn_mode) { FATAL("Multiple -U options not supported"); } - unicorn_mode = 1; + unicorn_mode = true; break; case 'W': /* Wine+QEMU mode */ if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; + fsrv->qemu_mode = true; + use_wine = true; break; @@ -930,20 +954,20 @@ int main(int argc, char **argv_orig, char **envp) { /* Secret undocumented mode. Writes output in raw binary format similar to that dumped by afl-fuzz in cmplog_mode = 0; u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1); - shm_fuzz->shmemfuzz_mode = 1; + shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } #ifdef USEMMAP setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1); @@ -1062,7 +1086,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv(SHM_FUZZ_ENV_VAR, shm_str, 1); ck_free(shm_str); #endif - fsrv->support_shmem_fuzz = 1; + fsrv->support_shmem_fuzz = true; fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); @@ -1114,7 +1138,7 @@ int main(int argc, char **argv_orig, char **envp) { struct stat statbuf; #endif - if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1; + if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -1153,8 +1177,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((coverage_map = (u8 *)malloc(map_size)) == NULL) FATAL("coult not grab memory"); - edges_only = 0; - raw_instr_output = 1; + edges_only = false; + raw_instr_output = true; } -- cgit 1.4.1 From 5997a4fc09163c1baa186f5a9d00c4c8668a72b1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 May 2021 10:26:27 +0200 Subject: fix llvm-dict2file --- GNUmakefile | 10 +++++----- docs/Changelog.md | 1 + instrumentation/afl-llvm-dict2file.so.cc | 5 ++++- qemu_mode/libqasan/libqasan.c | 5 ++--- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index 9d98aa00..270746b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -503,21 +503,21 @@ code-format: ./.custom-format.py -i instrumentation/*.h ./.custom-format.py -i instrumentation/*.cc ./.custom-format.py -i instrumentation/*.c + ./.custom-format.py -i *.h + ./.custom-format.py -i *.c @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( ./.custom-format.py -i utils/*/*.c* ./.custom-format.py -i utils/*/*.h ./.custom-format.py -i test/*.c + ./.custom-format.py -i frida_mode/src/*.c + ./.custom-format.py -i frida_mode/include/*.h + -./.custom-format.py -i frida_mode/src/*/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc ./.custom-format.py -i qemu_mode/libcompcov/*.h ./.custom-format.py -i qemu_mode/libqasan/*.c ./.custom-format.py -i qemu_mode/libqasan/*.h - ./.custom-format.py -i frida_mode/src/*.c - ./.custom-format.py -i frida_mode/include/*.h - -./.custom-format.py -i frida_mode/src/*/*.c - ./.custom-format.py -i *.h - ./.custom-format.py -i *.c .PHONY: test_build diff --git a/docs/Changelog.md b/docs/Changelog.md index 1114a834..282b34cf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -41,6 +41,7 @@ sending a mail to . - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - Fixed a crash in llvm dict2file when a strncmp length was -1 - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index c954054b..e2b44b21 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -426,7 +426,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { ConstantInt *ilen = dyn_cast(op2); if (ilen) { - uint64_t literalLength = Str2.size(); + uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); if (literalLength + 1 == optLength) { @@ -434,6 +434,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } + if (optLength > Str2.length()) { optLength = Str2.length(); } + } valueMap[Str1P] = new std::string(Str2); @@ -532,6 +534,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length()) { optLen = thestring.length(); } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index 2ac0c861..a64db10f 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -69,9 +69,8 @@ __attribute__((constructor)) void __libqasan_init() { __libqasan_is_initialized = 1; __libqasan_init_hooks(); - - if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) - __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); #ifdef DEBUG __qasan_debug = getenv("QASAN_DEBUG") != NULL; -- cgit 1.4.1 From 3844e7949283aa70aac14acf4a33c39b31254c8e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 21 May 2021 11:01:31 +0200 Subject: push to stable (#931) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza --- GNUmakefile | 10 +++---- docs/Changelog.md | 1 + frida_mode/GNUmakefile | 4 ++- frida_mode/src/persistent/persistent_x64.c | 46 ++++-------------------------- frida_mode/src/persistent/persistent_x86.c | 40 +++++--------------------- instrumentation/afl-llvm-dict2file.so.cc | 5 +++- qemu_mode/libqasan/libqasan.c | 2 ++ 7 files changed, 28 insertions(+), 80 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index 9d98aa00..270746b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -503,21 +503,21 @@ code-format: ./.custom-format.py -i instrumentation/*.h ./.custom-format.py -i instrumentation/*.cc ./.custom-format.py -i instrumentation/*.c + ./.custom-format.py -i *.h + ./.custom-format.py -i *.c @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( ./.custom-format.py -i utils/*/*.c* ./.custom-format.py -i utils/*/*.h ./.custom-format.py -i test/*.c + ./.custom-format.py -i frida_mode/src/*.c + ./.custom-format.py -i frida_mode/include/*.h + -./.custom-format.py -i frida_mode/src/*/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc ./.custom-format.py -i qemu_mode/libcompcov/*.h ./.custom-format.py -i qemu_mode/libqasan/*.c ./.custom-format.py -i qemu_mode/libqasan/*.h - ./.custom-format.py -i frida_mode/src/*.c - ./.custom-format.py -i frida_mode/include/*.h - -./.custom-format.py -i frida_mode/src/*/*.c - ./.custom-format.py -i *.h - ./.custom-format.py -i *.c .PHONY: test_build diff --git a/docs/Changelog.md b/docs/Changelog.md index 1114a834..282b34cf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -41,6 +41,7 @@ sending a mail to . - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - Fixed a crash in llvm dict2file when a strncmp length was -1 - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index bc77a451..20fbb544 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -93,7 +93,9 @@ AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o ############################## ALL ############################################# all: $(FRIDA_TRACE) - make -C $(ROOT) + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all 32: CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index 49f1988c..aa772b7f 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -40,7 +40,6 @@ struct x86_64_regs { typedef struct x86_64_regs arch_api_regs; static arch_api_regs saved_regs = {0}; -static void * saved_return = NULL; gboolean persistent_is_supported(void) { @@ -183,43 +182,11 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw, } -static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) { +static void instrument_exit(GumX86Writer *cw) { - GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - -(GUM_RED_ZONE_SIZE)); - gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); - gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); - - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, - GUM_RED_ZONE_SIZE + 0x10); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, 0, GUM_REG_RBX); - - gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); - gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); - - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - (GUM_RED_ZONE_SIZE)); - -} - -static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) { - - GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - -(GUM_RED_ZONE_SIZE)); - - /* Place holder for ret */ - gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); - gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); - - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, saved_return_address); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RAX, GUM_REG_RAX, 0); - - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RSP, 0x8, GUM_REG_RAX); - gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); - gum_x86_writer_put_ret_imm(cw, GUM_RED_ZONE_SIZE); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(_exit)); + gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_RDI, 0); + gum_x86_writer_put_call_reg(cw, GUM_REG_RAX); } @@ -302,8 +269,7 @@ void persistent_prologue(GumStalkerOutput *output) { /* Stack must be 16-byte aligned per ABI */ instrument_persitent_save_regs(cw, &saved_regs); - /* Stash and pop the return value */ - instrument_save_ret(cw, &saved_return); + /* pop the return value */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8)); /* loop: */ @@ -329,7 +295,7 @@ void persistent_prologue(GumStalkerOutput *output) { /* done: */ gum_x86_writer_put_label(cw, done); - instrument_jump_ret(cw, &saved_return); + instrument_exit(cw); /* original: */ gum_x86_writer_put_label(cw, original); diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index bd7171b9..20a3dc42 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -39,7 +39,6 @@ struct x86_regs { typedef struct x86_regs arch_api_regs; static arch_api_regs saved_regs = {0}; -static void * saved_return = NULL; gboolean persistent_is_supported(void) { @@ -138,36 +137,12 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw, } -static void instrument_save_ret(GumX86Writer *cw, void **saved_return_ptr) { +static void instrument_exit(GumX86Writer *cw) { - GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); - - gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); - gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); - - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x8); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, 0, GUM_REG_EBX); - - gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX); - gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); - -} - -static void instrument_jump_ret(GumX86Writer *cw, void **saved_return_ptr) { - - GumAddress saved_return_address = GUM_ADDRESS(saved_return_ptr); - - /* Place holder for ret */ - gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); - gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); - - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, saved_return_address); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EAX, GUM_REG_EAX, 0); - - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_ESP, 0x4, GUM_REG_EAX); - gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); - gum_x86_writer_put_ret(cw); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(_exit)); + gum_x86_writer_put_mov_reg_u32(cw, GUM_REG_EDI, 0); + gum_x86_writer_put_push_reg(cw, GUM_REG_EDI); + gum_x86_writer_put_call_reg(cw, GUM_REG_EAX); } @@ -238,8 +213,7 @@ void persistent_prologue(GumStalkerOutput *output) { /* Stack must be 16-byte aligned per ABI */ instrument_persitent_save_regs(cw, &saved_regs); - /* Stash and pop the return value */ - instrument_save_ret(cw, &saved_return); + /* Pop the return value */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4)); /* loop: */ @@ -265,7 +239,7 @@ void persistent_prologue(GumStalkerOutput *output) { /* done: */ gum_x86_writer_put_label(cw, done); - instrument_jump_ret(cw, &saved_return); + instrument_exit(cw); /* original: */ gum_x86_writer_put_label(cw, original); diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index c954054b..e2b44b21 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -426,7 +426,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { ConstantInt *ilen = dyn_cast(op2); if (ilen) { - uint64_t literalLength = Str2.size(); + uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); if (literalLength + 1 == optLength) { @@ -434,6 +434,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } + if (optLength > Str2.length()) { optLength = Str2.length(); } + } valueMap[Str1P] = new std::string(Str2); @@ -532,6 +534,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length()) { optLen = thestring.length(); } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index 2ac0c861..d4742e3e 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -73,6 +73,8 @@ __attribute__((constructor)) void __libqasan_init() { if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); + #ifdef DEBUG __qasan_debug = getenv("QASAN_DEBUG") != NULL; #endif -- cgit 1.4.1 From bd1ceb42c4e445babe38a129abf913d447fce9ea Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 22 May 2021 11:43:09 +0200 Subject: added info about showmap queue directions --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 282b34cf..dfd5c393 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -54,6 +54,7 @@ sending a mail to . - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From 9e6e7e8fe8e3e185c9ad4bde030fe760ee1528b0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 22 May 2021 12:08:19 +0200 Subject: update binary-only doc --- docs/binaryonly_fuzzing.md | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'docs') diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 787d970d..2f5dd614 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -42,6 +42,23 @@ As it is included in afl++ this needs no URL. +## AFL FRIDA + + In frida_mode you can fuzz binary-only targets easily like with QEMU, + with the advantage that frida_mode also works on MacOS (both intel and M1). + + If you want to fuzz a binary-only library then you can fuzz it with + frida-gum via utils/afl_frida/, you will have to write a harness to + call the target function in the library, use afl-frida.c as a template. + + Both come with afl++ so this needs no URL. + + You can also perform remote fuzzing with frida, e.g. if you want to fuzz + on iPhone or Android devices, for this you can use + [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) + as an intermediate that uses afl++ for fuzzing. + + ## WINE+QEMU Wine mode can run Win32 PE binaries with the QEMU instrumentation. @@ -62,13 +79,6 @@ As it is included in afl++ this needs no URL. -## AFL FRIDA - - If you want to fuzz a binary-only shared library then you can fuzz it with - frida-gum via utils/afl_frida/, you will have to write a harness to - call the target function in the library, use afl-frida.c as a template. - - ## AFL UNTRACER If you want to fuzz a binary-only shared library then you can fuzz it with @@ -157,19 +167,6 @@ If anyone finds any coresight implementation for afl please ping me: vh@thc.org -## FRIDA - - Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio. - What is special is that it is written Python, and scripted with Javascript. - It is mostly used to reverse binaries on mobile phones however can be used - everywhere. - - There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer) - - There is also an early implementation in an AFL++ test branch: - [https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida) - - ## PIN & DYNAMORIO Pintool and Dynamorio are dynamic instrumentation engines, and they can be @@ -205,7 +202,8 @@ * QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym) * Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore) * S2E: [https://github.com/S2E](https://github.com/S2E) - * Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Tinyinst: [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Jackalope: [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope) * ... please send me any missing that are good -- cgit 1.4.1 From 58e39ecd8f601191a98d067d5567559de931c32c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 22 May 2021 12:15:09 +0200 Subject: turn off map size detection if skip_bin_check is set --- docs/env_variables.md | 1 + src/afl-common.c | 4 ++++ src/afl-fuzz.c | 8 +++----- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index c3efa0c0..def1e297 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -355,6 +355,7 @@ checks or alter some of the more exotic semantics of the tool: and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting to instruct afl-fuzz to still follow the fork server protocol without expecting any instrumentation data in return. + Note that this also turns off auto map size detection. - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything diff --git a/src/afl-common.c b/src/afl-common.c index 0fb1462e..8826de70 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1110,6 +1110,10 @@ u32 get_map_size(void) { if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); } + } else if (getenv("AFL_SKIP_BIN_CHECK")) { + + map_size = MAP_SIZE; + } return map_size; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 37659831..76c4ca37 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -238,7 +238,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" - "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" + "AFL_SKIP_BIN_CHECK: skip afl compatability checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" @@ -1718,8 +1718,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->fsrv.frida_mode && - !((map_size == MAP_SIZE || map_size == 65536) && - afl->afl_env.afl_skip_bin_check)) { + !afl->afl_env.afl_skip_bin_check) { if (map_size <= DEFAULT_SHMEM_SIZE) { @@ -1780,8 +1779,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode && - !((map_size == MAP_SIZE || map_size == 65536) && - afl->afl_env.afl_skip_bin_check)) { + !afl->afl_env.afl_skip_bin_check) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; -- cgit 1.4.1 From 07c8024ef11686c58c623d621f236c5312689d1b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 24 May 2021 14:05:34 +0200 Subject: add libafl to binary-only doc --- README.md | 28 ++++++++++++++++++++++------ docs/binaryonly_fuzzing.md | 20 +++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 0b89845c..501f0591 100644 --- a/README.md +++ b/README.md @@ -791,16 +791,19 @@ How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz]( When source code is *NOT* available, afl++ offers various support for fast, on-the-fly instrumentation of black-box binaries. -If you do not have to use Unicorn the following setup is recommended: +If you do not have to use Unicorn the following setup is recommended to use +qemu_mode: * run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`) * run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`) * run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`) +Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the +LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc. +use a binary rewriter like afl-dyninst, retrowrite, zaflr, fibre, etc. -For Qemu mode, check out the persistent mode and snapshot features, they give -a huge speed improvement! +For Qemu and Frida mode, check out the persistent mode and snapshot features, +they give a huge speed improvement! ### QEMU @@ -812,8 +815,7 @@ feature by doing: cd qemu_mode ./build_qemu_support.sh ``` -For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) - -check out the snapshot feature! :-) +For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md). If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md). The mode is approximately 2-5x slower than compile-time instrumentation, and is less conducive to parallelization. @@ -824,6 +826,20 @@ the speed compared to qemu_mode (but slower than persistent mode). Note that several other binary rewriters exist, all with their advantages and caveats. +### Frida + +Frida mode is sometimes faster and sometimes slower than Qemu mode. +It is also newer, lacks COMPCOV, but supports MacOS. + +```shell +cd frida_mode +make +``` +For additional instructions and caveats, see [frida_mode/README.md](frida_mode/README.md). +If possible you should use the persistent mode, see [qemu_frida/README.persistent.md](qemu_frida/README.persistent.md). +The mode is approximately 2-5x slower than compile-time instrumentation, and is +less conducive to parallelization. + ### Unicorn For non-Linux binaries you can use afl++'s unicorn mode which can emulate diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 2f5dd614..bab64a30 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -41,15 +41,20 @@ As it is included in afl++ this needs no URL. + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which will support QEMU + very too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + ## AFL FRIDA - In frida_mode you can fuzz binary-only targets easily like with QEMU, - with the advantage that frida_mode also works on MacOS (both intel and M1). + In frida_mode you can fuzz binary-only targets easily like with QEMU, + with the advantage that frida_mode also works on MacOS (both intel and M1). - If you want to fuzz a binary-only library then you can fuzz it with - frida-gum via utils/afl_frida/, you will have to write a harness to - call the target function in the library, use afl-frida.c as a template. + If you want to fuzz a binary-only library then you can fuzz it with + frida-gum via utils/afl_frida/, you will have to write a harness to + call the target function in the library, use afl-frida.c as a template. Both come with afl++ so this needs no URL. @@ -58,6 +63,11 @@ [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) as an intermediate that uses afl++ for fuzzing. + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which supports Frida too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + Working examples already exist :-) + ## WINE+QEMU -- cgit 1.4.1 From 95f47ac3a4d23b28a573a0614893d7aac5f5d4b4 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 24 May 2021 14:06:46 +0200 Subject: Final push to stable (#936) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator --- .gitignore | 1 + README.md | 31 +++++++++++++++++++++------- TODO.md | 2 +- afl-system-config | 33 +++++++++++++++++++++--------- custom_mutators/README.md | 3 +++ docs/Changelog.md | 1 + docs/binaryonly_fuzzing.md | 50 +++++++++++++++++++++++++++------------------- docs/env_variables.md | 1 + qemu_mode/README.wine.md | 21 +++++++++++++++++++ src/afl-cc.c | 2 +- src/afl-common.c | 4 ++++ src/afl-fuzz-extras.c | 14 +++++++++++++ src/afl-fuzz-init.c | 10 +++++++--- src/afl-fuzz.c | 11 +++++----- src/afl-showmap.c | 33 ++++++++++++++++++------------ 15 files changed, 157 insertions(+), 60 deletions(-) create mode 100644 qemu_mode/README.wine.md (limited to 'docs') diff --git a/.gitignore b/.gitignore index c8d29e50..8c420b5e 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,4 @@ gmon.out afl-frida-trace.so utils/afl_network_proxy/afl-network-client utils/afl_network_proxy/afl-network-server +*.o.tmp diff --git a/README.md b/README.md index 5d5510d2..501f0591 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,7 @@ Here are some good writeups to show how to effectively use AFL++: If you are interested in fuzzing structured data (where you define what the structure is), these links have you covered: * Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator) + * libprotobuf for afl++: [https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator) * libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator) * libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator) @@ -436,7 +437,7 @@ described in [instrumentation/README.lto.md](instrumentation/README.lto.md). ##### cmake For `cmake` build systems this is usually done by: -`mkdir build; cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..` +`mkdir build; cd build; cmake -DCMAKE_C_COMPILER=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ ..` Note that if you are using the (better) afl-clang-lto compiler you also have to set AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as is @@ -790,16 +791,19 @@ How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz]( When source code is *NOT* available, afl++ offers various support for fast, on-the-fly instrumentation of black-box binaries. -If you do not have to use Unicorn the following setup is recommended: +If you do not have to use Unicorn the following setup is recommended to use +qemu_mode: * run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`) * run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`) * run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`) +Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the +LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, zipr, fibre, etc. +use a binary rewriter like afl-dyninst, retrowrite, zaflr, fibre, etc. -For Qemu mode, check out the persistent mode and snapshot features, they give -a huge speed improvement! +For Qemu and Frida mode, check out the persistent mode and snapshot features, +they give a huge speed improvement! ### QEMU @@ -811,8 +815,7 @@ feature by doing: cd qemu_mode ./build_qemu_support.sh ``` -For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md) - -check out the snapshot feature! :-) +For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md). If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md). The mode is approximately 2-5x slower than compile-time instrumentation, and is less conducive to parallelization. @@ -823,6 +826,20 @@ the speed compared to qemu_mode (but slower than persistent mode). Note that several other binary rewriters exist, all with their advantages and caveats. +### Frida + +Frida mode is sometimes faster and sometimes slower than Qemu mode. +It is also newer, lacks COMPCOV, but supports MacOS. + +```shell +cd frida_mode +make +``` +For additional instructions and caveats, see [frida_mode/README.md](frida_mode/README.md). +If possible you should use the persistent mode, see [qemu_frida/README.persistent.md](qemu_frida/README.persistent.md). +The mode is approximately 2-5x slower than compile-time instrumentation, and is +less conducive to parallelization. + ### Unicorn For non-Linux binaries you can use afl++'s unicorn mode which can emulate diff --git a/TODO.md b/TODO.md index 5a5e7c4e..398f3d11 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,7 @@ - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - - CPU affinity for many cores? There seems to be an issue > 96 cores + - put fuzz target in top line of UI - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - afl_custom_splice() diff --git a/afl-system-config b/afl-system-config index e08871ac..e149e4cd 100755 --- a/afl-system-config +++ b/afl-system-config @@ -7,7 +7,7 @@ test "$1" = "-h" -o "$1" = "-hh" && { echo afl-system-config has no command line options echo echo afl-system reconfigures the system to a high performance fuzzing state - echo WARNING: this reduces the security of the system + echo "WARNING: this reduces the security of the system!" echo exit 1 } @@ -15,11 +15,14 @@ test "$1" = "-h" -o "$1" = "-hh" && { DONE= PLATFORM=`uname -s` echo This reconfigures the system to have a better fuzzing performance. +echo "WARNING: this reduces the security of the system!" +echo if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then echo "Warning: you need to be root to run this!" # we do not exit as other mechanisms exist that allows to do this than # being root. let the errors speak for themselves. fi +sleep 1 if [ "$PLATFORM" = "Linux" ] ; then { sysctl -w kernel.core_uses_pid=0 @@ -38,12 +41,17 @@ if [ "$PLATFORM" = "Linux" ] ; then test -e /sys/devices/system/cpu/intel_pstate/no_turbo && echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cpu/cpufreq/boost test -e /sys/devices/system/cpu/intel_pstate/max_perf_pct && echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct + test -n "$(which auditctl)" && auditctl -a never,task >/dev/null 2>&1 } > /dev/null echo Settings applied. + echo dmesg | egrep -q 'nospectre_v2|spectre_v2=off' || { echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 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 srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"' + echo } + echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed + echo DONE=1 fi if [ "$PLATFORM" = "FreeBSD" ] ; then @@ -52,6 +60,7 @@ if [ "$PLATFORM" = "FreeBSD" ] ; then sysctl kern.elf64.aslr.enable=0 } > /dev/null echo Settings applied. + echo cat < /dev/null echo Settings applied. + echo DONE=1 fi if [ "$PLATFORM" = "Darwin" ] ; then sysctl kern.sysv.shmmax=8388608 sysctl kern.sysv.shmseg=48 sysctl kern.sysv.shmall=98304 + echo Settings applied. + echo if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then - echo We unload the default crash reporter here + echo + echo Unloading the default crash reporter SL=/System/Library; PL=com.apple.ReportCrash - launchctl unload -w ${SL}/LaunchAgents/${PL}.plist - sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist - echo Settings applied. + launchctl unload -w ${SL}/LaunchAgents/${PL}.plist >/dev/null 2>&1 + sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist >/dev/null 2>&1 + echo fi + echo It is recommended to disable System Integration Protection for increased performance. + echo DONE=1 fi if [ "$PLATFORM" = "Haiku" ] ; then @@ -108,7 +123,7 @@ if [ "$PLATFORM" = "Haiku" ] ; then [ -r ${SETTINGS} ] && grep -qE "default_action\s+kill" ${SETTINGS} && { echo "Nothing to do"; } || { \ echo We change the debug_server default_action from user to silently kill; \ [ ! -r ${SETTINGS} ] && echo "default_action kill" >${SETTINGS} || { mv ${SETTINGS} s.tmp; sed -e "s/default_action\s\s*user/default_action kill/" s.tmp > ${SETTINGS}; rm s.tmp; }; \ - echo Settings applied.; \ + echo Settings applied.; echo; \ } DONE=1 fi diff --git a/custom_mutators/README.md b/custom_mutators/README.md index 5e1d0fe6..13172cdc 100644 --- a/custom_mutators/README.md +++ b/custom_mutators/README.md @@ -54,3 +54,6 @@ https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4 has a transform function you need to fill for your protobuf format, however needs to be ported to the updated afl++ custom mutator API (not much work): https://github.com/thebabush/afl-libprotobuf-mutator + +same as above but is for current afl++: +https://github.com/P1umer/AFLplusplus-protobuf-mutator diff --git a/docs/Changelog.md b/docs/Changelog.md index 282b34cf..dfd5c393 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -54,6 +54,7 @@ sending a mail to . - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 787d970d..bab64a30 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -41,6 +41,33 @@ As it is included in afl++ this needs no URL. + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which will support QEMU + very too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + + +## AFL FRIDA + + In frida_mode you can fuzz binary-only targets easily like with QEMU, + with the advantage that frida_mode also works on MacOS (both intel and M1). + + If you want to fuzz a binary-only library then you can fuzz it with + frida-gum via utils/afl_frida/, you will have to write a harness to + call the target function in the library, use afl-frida.c as a template. + + Both come with afl++ so this needs no URL. + + You can also perform remote fuzzing with frida, e.g. if you want to fuzz + on iPhone or Android devices, for this you can use + [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) + as an intermediate that uses afl++ for fuzzing. + + If you like to code a customized fuzzer without much work, we highly + recommend to check out our sister project libafl which supports Frida too: + [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) + Working examples already exist :-) + ## WINE+QEMU @@ -62,13 +89,6 @@ As it is included in afl++ this needs no URL. -## AFL FRIDA - - If you want to fuzz a binary-only shared library then you can fuzz it with - frida-gum via utils/afl_frida/, you will have to write a harness to - call the target function in the library, use afl-frida.c as a template. - - ## AFL UNTRACER If you want to fuzz a binary-only shared library then you can fuzz it with @@ -157,19 +177,6 @@ If anyone finds any coresight implementation for afl please ping me: vh@thc.org -## FRIDA - - Frida is a dynamic instrumentation engine like Pintool, Dyninst and Dynamorio. - What is special is that it is written Python, and scripted with Javascript. - It is mostly used to reverse binaries on mobile phones however can be used - everywhere. - - There is a WIP fuzzer available at [https://github.com/andreafioraldi/frida-fuzzer](https://github.com/andreafioraldi/frida-fuzzer) - - There is also an early implementation in an AFL++ test branch: - [https://github.com/AFLplusplus/AFLplusplus/tree/frida](https://github.com/AFLplusplus/AFLplusplus/tree/frida) - - ## PIN & DYNAMORIO Pintool and Dynamorio are dynamic instrumentation engines, and they can be @@ -205,7 +212,8 @@ * QSYM: [https://github.com/sslab-gatech/qsym](https://github.com/sslab-gatech/qsym) * Manticore: [https://github.com/trailofbits/manticore](https://github.com/trailofbits/manticore) * S2E: [https://github.com/S2E](https://github.com/S2E) - * Tinyinst [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Tinyinst: [https://github.com/googleprojectzero/TinyInst](https://github.com/googleprojectzero/TinyInst) (Mac/Windows only) + * Jackalope: [https://github.com/googleprojectzero/Jackalope](https://github.com/googleprojectzero/Jackalope) * ... please send me any missing that are good diff --git a/docs/env_variables.md b/docs/env_variables.md index c3efa0c0..def1e297 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -355,6 +355,7 @@ checks or alter some of the more exotic semantics of the tool: and shell scripts; and `AFL_DUMB_FORKSRV` in conjunction with the `-n` setting to instruct afl-fuzz to still follow the fork server protocol without expecting any instrumentation data in return. + Note that this also turns off auto map size detection. - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything diff --git a/qemu_mode/README.wine.md b/qemu_mode/README.wine.md new file mode 100644 index 00000000..567901cd --- /dev/null +++ b/qemu_mode/README.wine.md @@ -0,0 +1,21 @@ +# How to troubleshoot AFL++'s wine mode + +## 1) Debugging +To turn on wine debugging use the `WINEDEBUG` environment variable, +e.g. `WINEDEBUG=+timestamp,+tid,+loaddll`. + +## 2) LoadLibraryA workaround +The forked process fails to load libraries loaded via `LoadLibrary` +if the load happens after the entry point (error code: 87). To resolve +this issue, one needs to load any external libraries before the fork happens. + +An early DLL load can be achieved by adding the DLL name into the `Import Directory` +in the PE file. Such an entry can be added manually in any PE editor. + +Alternativly, one can generate a `.lib` file from the DLL exports and link +them together with the harness to create an entry in the `Import Directory`. +Use `dumpbin /exports .dll` to extract the exports and paste the +exported function names into a `.def` file. Use `lib /def: /OUT:` +to generate a `.lib` and add the library to the linker options. Once the usage of +an export is detected (`__declspec(dllimport)`), the +linker adds the early DLL load. \ No newline at end of file diff --git a/src/afl-cc.c b/src/afl-cc.c index ff7b5219..ebe11525 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1640,7 +1640,7 @@ int main(int argc, char **argv, char **envp) { " yes\n" " [LLVM] llvm: %s%s\n" " PCGUARD %s yes yes module yes yes " - "extern\n" + "yes\n" " CLASSIC %s no yes module yes yes " "yes\n" " - NORMAL\n" diff --git a/src/afl-common.c b/src/afl-common.c index 0fb1462e..8826de70 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1110,6 +1110,10 @@ u32 get_map_size(void) { if (map_size % 64) { map_size = (((map_size >> 6) + 1) << 6); } + } else if (getenv("AFL_SKIP_BIN_CHECK")) { + + map_size = MAP_SIZE; + } return map_size; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 6091db15..584241d4 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -130,6 +130,20 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, } + /* Skip [number] */ + + if (*lptr == '[') { + + do { + + ++lptr; + + } while (*lptr >= '0' && *lptr <= '9'); + + if (*lptr == ']') { ++lptr; } + + } + /* Skip whitespace and = signs. */ while (isspace(*lptr) || *lptr == '=') { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index c43bcc2b..b277802b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2728,11 +2728,15 @@ void check_binary(afl_state_t *afl, u8 *fname) { " When source code is not available, you may be able to leverage " "QEMU\n" " mode support. Consult the README.md for tips on how to enable " - "this.\n" + "this.\n\n" + + " If your target is an instrumented binary (e.g. with zafl, " + "retrowrite,\n" + " etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n" " (It is also possible to use afl-fuzz as a traditional, " - "non-instrumented fuzzer.\n" - " For that, you can use the -n option - but expect much worse " + "non-instrumented\n" + " fuzzer. For that use the -n option - but expect much worse " "results.)\n", doc_path); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5f939115..35fb2d04 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -238,7 +238,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" - "AFL_SKIP_BIN_CHECK: skip the check, if the target is an executable\n" + "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" @@ -1717,10 +1717,10 @@ int main(int argc, char **argv_orig, char **envp) { afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode); if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->unicorn_mode) { + !afl->unicorn_mode && !afl->fsrv.frida_mode && + !afl->afl_env.afl_skip_bin_check) { - if (map_size <= DEFAULT_SHMEM_SIZE && !afl->non_instrumented_mode && - !afl->fsrv.qemu_mode && !afl->unicorn_mode) { + if (map_size <= DEFAULT_SHMEM_SIZE) { afl->fsrv.map_size = DEFAULT_SHMEM_SIZE; // dummy temporary value char vbuf[16]; @@ -1778,7 +1778,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((map_size <= DEFAULT_SHMEM_SIZE || afl->cmplog_fsrv.map_size < map_size) && !afl->non_instrumented_mode && !afl->fsrv.qemu_mode && - !afl->fsrv.frida_mode && !afl->unicorn_mode) { + !afl->fsrv.frida_mode && !afl->unicorn_mode && + !afl->afl_env.afl_skip_bin_check) { afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE); char vbuf[16]; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 9b4d21a5..d7af668c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #ifndef USEMMAP @@ -1103,6 +1104,9 @@ int main(int argc, char **argv_orig, char **envp) { : 0); be_quiet = save_be_quiet; + fsrv->kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + if (new_map_size) { // only reinitialize when it makes sense @@ -1129,8 +1133,9 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent *dir_ent; + DIR * dir_in, *dir_out = NULL; + struct dirent **file_list; + // int done = 0; u8 infile[PATH_MAX], outfile[PATH_MAX]; u8 wait_for_gdb = 0; @@ -1155,12 +1160,6 @@ int main(int argc, char **argv_orig, char **envp) { ck_free(dn); if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - if (!(dir_in = opendir(in_dir))) { - - PFATAL("cannot open directory %s", in_dir); - - } - if (!collect_coverage) { if (!(dir_out = opendir(out_file))) { @@ -1215,9 +1214,6 @@ int main(int argc, char **argv_orig, char **envp) { } - fsrv->kill_signal = - parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); - if (getenv("AFL_CRASH_EXITCODE")) { long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10); @@ -1246,7 +1242,16 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - while ((dir_ent = readdir(dir_in))) { + int file_count = scandir(in_dir, &file_list, NULL, alphasort); + if (file_count < 0) { + + PFATAL("Failed to read from input dir at %s\n", in_dir); + + } + + for (int i = 0; i < file_count; i++) { + + struct dirent *dir_ent = file_list[i]; if (dir_ent->d_name[0] == '.') { @@ -1293,9 +1298,11 @@ int main(int argc, char **argv_orig, char **envp) { } + free(file_list); + file_list = NULL; + if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } - closedir(dir_in); if (dir_out) { closedir(dir_out); } if (collect_coverage) { -- cgit 1.4.1 From 109383f43830010c36b704c682ee537e6474d25a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 09:08:31 +0200 Subject: less executions on variable paths --- docs/Changelog.md | 2 ++ include/config.h | 4 ++-- src/afl-fuzz-run.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index dfd5c393..33d37067 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times + instead of 40 - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/include/config.h b/include/config.h index aa24ea6c..80cdb684 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,7 @@ cases that show variable behavior): */ #define CAL_CYCLES 8U -#define CAL_CYCLES_LONG 40U +#define CAL_CYCLES_LONG 20U /* Number of subsequent timeouts before abandoning an input file: */ @@ -163,7 +163,7 @@ /* Maximum number of unique hangs or crashes to record: */ #define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 5000U +#define KEEP_UNIQUE_CRASH 10000U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6e5210b8..5a481639 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -410,7 +410,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = CAL_CYCLES_LONG; + afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; } else { -- cgit 1.4.1 From 8e75adfee5574d6d0dd7fd73e9c0899f3162c964 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 09:22:50 +0200 Subject: AFL_SKIP_CRASHES is obsolete since 3.0 --- docs/env_variables.md | 5 ----- include/afl-fuzz.h | 2 +- src/afl-fuzz-init.c | 30 +++--------------------------- src/afl-fuzz-state.c | 3 +-- src/afl-fuzz.c | 2 +- 5 files changed, 6 insertions(+), 36 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index def1e297..442b0dd0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -315,11 +315,6 @@ checks or alter some of the more exotic semantics of the tool: - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. - - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input - queue. This can help with rare situations where a program crashes only - intermittently, but it's not really recommended under normal operating - conditions. - - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for deciding if a particular test case is a "hang". The default is 1 second or the value of the `-t` parameter, whichever is larger. Dialing the value diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 72f956b9..e9a72fc2 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -388,7 +388,7 @@ typedef struct afl_env_vars { afl_exit_on_seed_issues; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, - *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, + *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b277802b..f2d1fb9b 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -823,7 +823,6 @@ void perform_dry_run(afl_state_t *afl) { struct queue_entry *q; u32 cal_failures = 0, idx; - u8 * skip_crashes = afl->afl_env.afl_skip_crashes; u8 * use_mem; for (idx = 0; idx < afl->queued_paths; idx++) { @@ -923,27 +922,6 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } - if (skip_crashes) { - - if (afl->fsrv.uses_crash_exitcode) { - - WARNF( - "Test case results in a crash or AFL_CRASH_EXITCODE %d " - "(skipping)", - (int)(s8)afl->fsrv.crash_exitcode); - - } else { - - WARNF("Test case results in a crash (skipping)"); - - } - - q->cal_failed = CAL_CHANCES; - ++cal_failures; - break; - - } - if (afl->fsrv.mem_limit) { u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -1117,14 +1095,12 @@ void perform_dry_run(afl_state_t *afl) { if (cal_failures == afl->queued_paths) { - FATAL("All test cases time out%s, giving up!", - skip_crashes ? " or crash" : ""); + FATAL("All test cases time out or crash, giving up!"); } - WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, - ((double)cal_failures) * 100 / afl->queued_paths, - skip_crashes ? " or crashes" : ""); + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.", + cal_failures, ((double)cal_failures) * 100 / afl->queued_paths); if (cal_failures * 5 > afl->queued_paths) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index c886cb28..046d17d6 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -206,8 +206,7 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl_environment_variable_len)) { - afl->afl_env.afl_skip_crashes = - (u8 *)get_afl_env(afl_environment_variables[i]); + // we should mark this obsolete in a few versions } else if (!strncmp(env, "AFL_HANG_TMOUT", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 35fb2d04..3b6ac5e2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -240,7 +240,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" - "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" + //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" -- cgit 1.4.1 From 87b16c4460d34eb775660991732ca0ef0c2f8e78 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 10:45:24 +0200 Subject: add AFL_TRY_AFFINITY --- Dockerfile | 1 + README.md | 4 ++-- docs/Changelog.md | 10 ++++++---- docs/env_variables.md | 3 +++ include/afl-fuzz.h | 2 +- include/envs.h | 1 + src/afl-fuzz-init.c | 34 ++++++++++++++++++++++++---------- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 1 + 9 files changed, 46 insertions(+), 17 deletions(-) (limited to 'docs') diff --git a/Dockerfile b/Dockerfile index 8f89b9aa..9662ca7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 ENV LLVM_CONFIG=llvm-config-12 ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov diff --git a/README.md b/README.md index cedf706c..69e2d14a 100644 --- a/README.md +++ b/README.md @@ -679,8 +679,8 @@ If you see that an important area or a feature has not been covered so far then try to find an input that is able to reach that and start a new secondary in that fuzzing campaign with that seed as input, let it run for a few minutes, then terminate it. The main node will pick it up and make it available to the -other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no -free core. +other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or +`export AFL_TRY_AFFINITY=1` if you have no free core. Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. diff --git a/docs/Changelog.md b/docs/Changelog.md index 33d37067..bbe55e3e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,10 +33,12 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after - no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times - instead of 40 + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing + after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of 40 + - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if + it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 442b0dd0..a3267523 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -312,6 +312,9 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). + - Setting `AFL_TRY_AFFINITY` tries to attempts to bind to a specific CPU core + on Linux systems, but will not terminate if it fails. + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e9a72fc2..4aba3bdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -385,7 +385,7 @@ typedef struct afl_env_vars { afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, - afl_exit_on_seed_issues; + afl_exit_on_seed_issues, afl_try_affinity; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, diff --git a/include/envs.h b/include/envs.h index f1314bad..e7162c0f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -120,6 +120,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_INSTRUMENT_FILE", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", + "AFL_TRY_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index f2d1fb9b..88b5bc02 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 lockfile[PATH_MAX] = ""; s32 i; - if (afl->afl_env.afl_no_affinity) { + if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { if (afl->cpu_to_bind != -1) { @@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!bind_cpu(afl, afl->cpu_to_bind)) { - FATAL( - "Could not bind to requested CPU %d! Make sure you passed a valid " - "-b.", - afl->cpu_to_bind); + if (afl->afl_env.afl_try_affinity) { + + WARNF( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } else { + + FATAL( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } } @@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) { "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " "Starting\n" - " another fuzzer on this machine is probably a bad plan, but if " - "you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", - afl->cpu_core_count); - FATAL("No more free CPU cores"); + " another fuzzer on this machine is probably a bad plan.\n" + "%s", + afl->cpu_core_count, + afl->afl_env.afl_try_affinity ? "" + : " If you are sure, you can set " + "AFL_NO_AFFINITY and try again.\n"); + + if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 046d17d6..0658070e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -202,6 +202,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_affinity = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TRY_AFFINITY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_try_affinity = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_SKIP_CRASHES", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3b6ac5e2..bb970e5f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -220,6 +220,7 @@ static void usage(u8 *argv0, int more_help) { " then they are randomly selected instead all of them being\n" " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" -- cgit 1.4.1 From 654bc7bf32a81576596b0ca83c9b90e90598a815 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 25 May 2021 21:29:09 +0200 Subject: Typo --- docs/binaryonly_fuzzing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index bab64a30..11e1dbeb 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -43,7 +43,7 @@ If you like to code a customized fuzzer without much work, we highly recommend to check out our sister project libafl which will support QEMU - very too: + too: [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) -- cgit 1.4.1 From ad3dba047f5186b3b0941d33f0cd37e9ac218069 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 25 May 2021 21:52:11 +0200 Subject: Typo --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index bbe55e3e..f8831ff1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,7 +35,7 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated + - when AFL_FAST_CAL is set a variable path will now be calibrated 8 times instead of 40 - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails -- cgit 1.4.1 From 314c0357a7619087d00b06a4567b97f4a30bfbf9 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 25 May 2021 21:59:24 +0200 Subject: Typo/wording --- docs/env_variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index a3267523..7bbc0fdd 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -312,8 +312,8 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). - - Setting `AFL_TRY_AFFINITY` tries to attempts to bind to a specific CPU core - on Linux systems, but will not terminate if it fails. + - Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core + on Linux systems, but will not terminate if that fails. - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. -- cgit 1.4.1 From 3b93729213de46a3008709bd8170d5593394d8cb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 22:04:25 +0200 Subject: tweaks --- docs/Changelog.md | 4 ++-- docs/custom_mutators.md | 3 +++ src/afl-fuzz-python.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index f8831ff1..175c6c43 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,8 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will now be calibrated - 8 times instead of 40 + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of originally 40. Long calibration is now 20. - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails - afl-cc: diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 9d5381e8..3e3ae01d 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -92,6 +92,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): def introspection(): return string + +def deinit(): # optional for Python + pass ``` ### Custom Mutation diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 8760194c..3aa97635 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) - FATAL("deinit function not found in python module"); + WARNF("deinit function not found in python module"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { -- cgit 1.4.1 From a5e551ab917cef708363483070eb62c55897cf3b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 23:49:14 +0200 Subject: typos --- docs/Changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 175c6c43..594637fb 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,7 +35,7 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated + - when AFL_FAST_CAL is set a variable path will now be calibrated 8 times instead of originally 40. Long calibration is now 20. - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails @@ -57,7 +57,8 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the + current filename - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) -- cgit 1.4.1 From 8e86f7ad803e571bcd275d2aca597997ab0e4d2c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 28 May 2021 13:35:05 +0200 Subject: add --afl-noopt to afl-cc --- docs/Changelog.md | 1 + src/afl-cc.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 594637fb..298a3998 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -46,6 +46,7 @@ sending a mail to . - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - Fixed a crash in llvm dict2file when a strncmp length was -1 + - added --afl-noopt support - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/src/afl-cc.c b/src/afl-cc.c index ebe11525..8af8e7b0 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1224,6 +1224,14 @@ int main(int argc, char **argv, char **envp) { if (strncmp(argv[i], "--afl", 5) == 0) { + if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) { + + passthrough = 1; + argv[i] = "-g"; // we have to overwrite it, -g is always good + continue; + + } + if (compiler_mode) WARNF( "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " @@ -1821,6 +1829,12 @@ int main(int argc, char **argv, char **envp) { "If anything fails - be sure to read README.lto.md!\n"); #endif + SAYF( + "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. " + "(this is helpful\n" + "in some build systems if you do not want to instrument " + "everything.\n"); + } SAYF( -- cgit 1.4.1 From de7370c0e966498ed95ab8a68ce57f6a1d10c21b Mon Sep 17 00:00:00 2001 From: Dag Heyman Kajevic Date: Fri, 28 May 2021 22:17:43 +0200 Subject: docs: fix link to README in QuickStartGuide (#946) --- docs/QuickStartGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index 10be409a..d1966170 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -1,6 +1,6 @@ # AFL quick start guide -You should read [README.md](README.md) - it's pretty short. If you really can't, here's +You should read [README.md](../README.md) - it's pretty short. If you really can't, here's how to hit the ground running: 1) Compile AFL with 'make'. If build fails, see [INSTALL.md](INSTALL.md) for tips. -- cgit 1.4.1 From 67293b298d2f6146022ac7adebdf17aebf27bea7 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 30 May 2021 02:06:05 +0200 Subject: final push to stable (really?) (#939) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic --- Dockerfile | 7 +- README.md | 12 +- afl-cmin | 8 +- afl-plot | 2 +- afl-whatsup | 13 +- docs/Changelog.md | 12 +- docs/QuickStartGuide.md | 2 +- docs/binaryonly_fuzzing.md | 2 +- docs/custom_mutators.md | 3 + docs/env_variables.md | 8 +- frida_mode/GNUmakefile | 3 - frida_mode/README.md | 148 +- frida_mode/include/instrument.h | 4 + frida_mode/include/output.h | 9 + frida_mode/include/persistent.h | 4 + frida_mode/include/ranges.h | 2 + frida_mode/include/stats.h | 28 + frida_mode/include/util.h | 2 +- frida_mode/src/instrument/instrument.c | 53 +- frida_mode/src/instrument/instrument_debug.c | 129 + frida_mode/src/main.c | 7 +- frida_mode/src/output.c | 45 + frida_mode/src/persistent/persistent.c | 34 +- frida_mode/src/persistent/persistent_arm32.c | 7 + frida_mode/src/persistent/persistent_arm64.c | 7 + frida_mode/src/persistent/persistent_x64.c | 19 +- frida_mode/src/persistent/persistent_x86.c | 15 + frida_mode/src/ranges.c | 69 +- frida_mode/src/stats/stats.c | 208 ++ frida_mode/src/stats/stats_arm.c | 36 + frida_mode/src/stats/stats_arm64.c | 36 + frida_mode/src/stats/stats_x64.c | 307 +++ frida_mode/src/stats/stats_x86.c | 36 + frida_mode/src/util.c | 13 +- frida_mode/test/deferred/GNUmakefile | 71 + frida_mode/test/deferred/Makefile | 13 + frida_mode/test/deferred/testinstr.c | 125 + frida_mode/test/libpcap/GNUmakefile | 188 ++ frida_mode/test/libpcap/Makefile | 1143 +++++++++ frida_mode/test/libpcap/aflpp_qemu_driver_hook.c | 97 + frida_mode/test/libpcap/get_symbol_addr.py | 36 + frida_mode/test/output/GNUmakefile | 47 + frida_mode/test/output/Makefile | 13 + frida_mode/test/output/frida_stderr.txt | 2824 +++++++++++++++++++++ frida_mode/test/output/frida_stdout.txt | 349 +++ frida_mode/test/output/testinstr.c | 112 + frida_mode/test/persistent_ret/GNUmakefile | 105 + frida_mode/test/persistent_ret/Makefile | 22 + frida_mode/test/persistent_ret/get_symbol_addr.py | 36 + frida_mode/test/persistent_ret/testinstr.c | 120 + frida_mode/test/re2/GNUmakefile | 170 ++ frida_mode/test/re2/Makefile | 22 + frida_mode/test/re2/aflpp_qemu_driver_hook.c | 97 + frida_mode/test/re2/get_symbol_addr.py | 36 + include/afl-fuzz.h | 4 +- include/config.h | 4 +- include/envs.h | 11 +- qemu_mode/README.md | 21 +- src/afl-cc.c | 14 + src/afl-fuzz-init.c | 64 +- src/afl-fuzz-python.c | 2 +- src/afl-fuzz-run.c | 2 +- src/afl-fuzz-state.c | 10 +- src/afl-fuzz.c | 28 +- src/afl-showmap.c | 3 + utils/aflpp_driver/README.md | 6 + utils/aflpp_driver/aflpp_driver.c | 44 +- 67 files changed, 6961 insertions(+), 168 deletions(-) create mode 100644 frida_mode/include/output.h create mode 100644 frida_mode/include/stats.h create mode 100644 frida_mode/src/instrument/instrument_debug.c create mode 100644 frida_mode/src/output.c create mode 100644 frida_mode/src/stats/stats.c create mode 100644 frida_mode/src/stats/stats_arm.c create mode 100644 frida_mode/src/stats/stats_arm64.c create mode 100644 frida_mode/src/stats/stats_x64.c create mode 100644 frida_mode/src/stats/stats_x86.c create mode 100644 frida_mode/test/deferred/GNUmakefile create mode 100644 frida_mode/test/deferred/Makefile create mode 100644 frida_mode/test/deferred/testinstr.c create mode 100644 frida_mode/test/libpcap/GNUmakefile create mode 100644 frida_mode/test/libpcap/Makefile create mode 100644 frida_mode/test/libpcap/aflpp_qemu_driver_hook.c create mode 100755 frida_mode/test/libpcap/get_symbol_addr.py create mode 100644 frida_mode/test/output/GNUmakefile create mode 100644 frida_mode/test/output/Makefile create mode 100644 frida_mode/test/output/frida_stderr.txt create mode 100644 frida_mode/test/output/frida_stdout.txt create mode 100644 frida_mode/test/output/testinstr.c create mode 100644 frida_mode/test/persistent_ret/GNUmakefile create mode 100644 frida_mode/test/persistent_ret/Makefile create mode 100755 frida_mode/test/persistent_ret/get_symbol_addr.py create mode 100644 frida_mode/test/persistent_ret/testinstr.c create mode 100644 frida_mode/test/re2/GNUmakefile create mode 100644 frida_mode/test/re2/Makefile create mode 100644 frida_mode/test/re2/aflpp_qemu_driver_hook.c create mode 100755 frida_mode/test/re2/get_symbol_addr.py (limited to 'docs') diff --git a/Dockerfile b/Dockerfile index 8f89b9aa..18fb6367 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 ENV LLVM_CONFIG=llvm-config-12 ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov @@ -61,8 +62,10 @@ WORKDIR /AFLplusplus RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \ make distrib && make install && make clean -RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc -RUN echo 'export PS1="[afl++]$PS1"' >> ~/.bashrc +RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' +RUN echo '. /etc/bash_completion' >> ~/.bashrc +RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc +RUN echo "export PS1='"'[afl++ \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc ENV IS_DOCKER="1" # Disabled until we have the container ready diff --git a/README.md b/README.md index 501f0591..69e2d14a 100644 --- a/README.md +++ b/README.md @@ -679,8 +679,8 @@ If you see that an important area or a feature has not been covered so far then try to find an input that is able to reach that and start a new secondary in that fuzzing campaign with that seed as input, let it run for a few minutes, then terminate it. The main node will pick it up and make it available to the -other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no -free core. +other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or +`export AFL_TRY_AFFINITY=1` if you have no free core. Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. @@ -800,10 +800,10 @@ Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, zaflr, fibre, etc. +use a binary rewriter like afl-dyninst, retrowrite, zaflr, etc. -For Qemu and Frida mode, check out the persistent mode and snapshot features, -they give a huge speed improvement! +For Qemu and Frida mode, check out the persistent mode, it gives a huge speed +improvement if it is possible to use. ### QEMU @@ -822,7 +822,7 @@ less conducive to parallelization. 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 (but slower than persistent mode). +the speed compared to qemu_mode (but slower than qemu persistent mode). Note that several other binary rewriters exist, all with their advantages and caveats. diff --git a/afl-cmin b/afl-cmin index adcbb221..9fa63ec6 100755 --- a/afl-cmin +++ b/afl-cmin @@ -119,13 +119,13 @@ function usage() { "Environment variables used:\n" \ "AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ -"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \ +"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ -"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" -"AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ +"AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ +"AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ "printed to stdout\n" \ -"AFL_SKIP_BIN_CHECK: skip check for target binary\n" +"AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n" exit 1 } diff --git a/afl-plot b/afl-plot index 26c8d1b7..60a351ab 100755 --- a/afl-plot +++ b/afl-plot @@ -127,7 +127,7 @@ set key outside set autoscale xfixmin set autoscale xfixmax -set xlabel "all times in UTC" font "small" +#set xlabel "all times in UTC" font "small" plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\ '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\ diff --git a/afl-whatsup b/afl-whatsup index be259829..9c2564c6 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -21,11 +21,11 @@ echo "$0 status check tool for afl-fuzz by Michal Zalewski" echo test "$1" = "-h" -o "$1" = "-hh" && { - echo "$0 [-s] [-d] output_directory" + echo "Usage: $0 [-s] [-d] afl_output_directory" echo echo Options: - echo -s - skip details and output summary results only - echo -d - include dead fuzzer stats + echo " -s - skip details and output summary results only" + echo " -d - include dead fuzzer stats" echo exit 1 } @@ -51,10 +51,11 @@ DIR="$1" if [ "$DIR" = "" ]; then - echo "Usage: $0 [-s] [-d] afl_sync_dir" 1>&2 + echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2 echo 1>&2 - echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2 - echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2 + echo Options: 1>&2 + echo " -s - skip details and output summary results only" 1>&2 + echo " -d - include dead fuzzer stats" 1>&2 echo 1>&2 exit 1 diff --git a/docs/Changelog.md b/docs/Changelog.md index dfd5c393..298a3998 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,8 +33,12 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after - no new paths have been found for n seconds + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing + after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will now be calibrated + 8 times instead of originally 40. Long calibration is now 20. + - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if + it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD @@ -42,6 +46,7 @@ sending a mail to . - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - Fixed a crash in llvm dict2file when a strncmp length was -1 + - added --afl-noopt support - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC @@ -53,7 +58,8 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the + current filename - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index 10be409a..d1966170 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -1,6 +1,6 @@ # AFL quick start guide -You should read [README.md](README.md) - it's pretty short. If you really can't, here's +You should read [README.md](../README.md) - it's pretty short. If you really can't, here's how to hit the ground running: 1) Compile AFL with 'make'. If build fails, see [INSTALL.md](INSTALL.md) for tips. diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index bab64a30..11e1dbeb 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -43,7 +43,7 @@ If you like to code a customized fuzzer without much work, we highly recommend to check out our sister project libafl which will support QEMU - very too: + too: [https://github.com/AFLplusplus/LibAFL](https://github.com/AFLplusplus/LibAFL) diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 9d5381e8..3e3ae01d 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -92,6 +92,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): def introspection(): return string + +def deinit(): # optional for Python + pass ``` ### Custom Mutation diff --git a/docs/env_variables.md b/docs/env_variables.md index def1e297..7bbc0fdd 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -312,14 +312,12 @@ checks or alter some of the more exotic semantics of the tool: on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). + - Setting `AFL_TRY_AFFINITY` tries to attempt binding to a specific CPU core + on Linux systems, but will not terminate if that fails. + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. - - `AFL_SKIP_CRASHES` causes AFL++ to tolerate crashing files in the input - queue. This can help with rare situations where a program crashes only - intermittently, but it's not really recommended under normal operating - conditions. - - Setting `AFL_HANG_TMOUT` allows you to specify a different timeout for deciding if a particular test case is a "hang". The default is 1 second or the value of the `-t` parameter, whichever is larger. Dialing the value diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 20fbb544..a0387cac 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -94,9 +94,6 @@ AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o all: $(FRIDA_TRACE) -32: - CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all - 32: CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all diff --git a/frida_mode/README.md b/frida_mode/README.md index ecce0bfd..0103a395 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -21,7 +21,7 @@ perhaps leverage some of its design and implementation. | Feature/Instrumentation | frida-mode | Notes | | -------------------------|:----------:|:--------------------------------------------:| | NeverZero | x | | - | Persistent Mode | x | (x86/x64 only)(Only on function boundaries) | + | Persistent Mode | x | (x86/x64 only)(Only on function boundaries) | | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | | CMPLOG | x | (x86/x64 only) | | Selective Instrumentation| x | | @@ -43,16 +43,16 @@ system does not support cross compilation. ## Getting Started -To build everything run `make`. To build for x86 run `make 32`. Note that in +To build everything run `make`. To build for x86 run `make 32`. Note that in x86 bit mode, it is not necessary for afl-fuzz to be built for 32-bit. However, the shared library for frida_mode must be since it is injected into the target process. Various tests can be found in subfolders within the `test/` directory. To use these, first run `make` to build any dependencies. Then run `make qemu` or -`make frida` to run on either QEMU of FRIDA mode respectively. To run frida -tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between -architectures it may be necessary to run `make clean` first for a given build +`make frida` to run on either QEMU of FRIDA mode respectively. To run frida +tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between +architectures it may be necessary to run `make clean` first for a given build target to remove previously generated binaries for a different architecture. ## Usage @@ -74,6 +74,8 @@ following options are currently supported: * `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR` * `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` * `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` +* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET` +* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET` To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`. @@ -127,34 +129,144 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent ## Advanced configuration options +* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks +and their instrumented counterparts during block compilation. +``` +*** + +Creating block for 0x7ffff7953313: + 0x7ffff7953313 mov qword ptr [rax], 0 + 0x7ffff795331a add rsp, 8 + 0x7ffff795331e ret + +Generated block 0x7ffff75e98e2 + 0x7ffff75e98e2 mov qword ptr [rax], 0 + 0x7ffff75e98e9 add rsp, 8 + 0x7ffff75e98ed lea rsp, [rsp - 0x80] + 0x7ffff75e98f5 push rcx + 0x7ffff75e98f6 movabs rcx, 0x7ffff795331e + 0x7ffff75e9900 jmp 0x7ffff75e9384 + + +*** +``` * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. -* `AFL_FRIDA_INST_TRACE` - Generate some logging when running instrumented code. -Requires `AFL_FRIDA_INST_NO_OPTIMIZE`. - +* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks +`AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code +at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user +to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a +debugger. + +``` + +gdb \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=XXXXXXXXXX' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RET=XXXXXXXXXX' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ + --ex 'set environment AFL_DEBUG_CHILD=1' \ + --ex 'set environment LD_PRELOAD=afl-frida-trace.so' \ + --args [my arguments] + +``` +* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being +instrumented to the given file name. The statistics are written only for the +child process when new block is instrumented (when the +`AFL_FRIDA_STATS_INTERVAL` has expired). Note that simply because a new path is +found does not mean a new block needs to be compiled. It could simply be that +the existing blocks instrumented have been executed in a different order. +``` +stats +----- +Index: 2 +Pid: 1815944 +Time: 2021-05-28 15:26:41 +Blocks: 1985 +Instructions: 9192 +Avg Instructions / Block: 4 + +Call Immediates: 391 (4.25%) +Call Immediates Excluded: 65 (0.71%) +Call Register: 0 (0.00%) +Call Memory: 0 (0.00%) + +Jump Immediates: 202 (2.20%) +Jump Register: 10 (0.11%) +Jump Memory: 12 (0.13%) + +Conditional Jump Immediates: 1210 (13.16%) +Conditional Jump CX Immediate: 0 (0.00%) +Conditional Jump Register: 0 (0.00%) +Conditional Jump Memory: 0 (0.00%) + +Returns: 159 (0.00%) + +Rip Relative: 247 (0.00%) + +``` +* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics +information. Stats will be written whenever they are updated if the given +interval has elapsed since last time they were written. +* `AFL_FRIDA_STATS_TRANSITIONS` - Also dump the internal stalker counters to +stderr when the regular stats are written. Note that these stats are reset in +the child each time a new fork occurs since they are not stored in shared +memory. Unfortunately, these stats are internal to stalker, so this is the best +we can do for now. +``` +stats +----- +Index: 2 +Pid: 1816794 +Time: 2021-05-28 15:26:41 + + +total_transitions: 786 + call_imms: 97 + call_regs: 0 + call_mems: 0 + post_call_invokes: 86 + excluded_call_imms: 29 + ret_slow_paths: 23 + + jmp_imms: 58 + jmp_mems: 7 + jmp_regs: 26 + + jmp_cond_imms: 460 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +``` ## FASAN - Frida Address Sanitizer Mode Frida mode also supports FASAN. The design of this is actually quite simple and very similar to that used when instrumenting applications compiled from source. ### Address Sanitizer Basics -When Address Sanitizer is used to instrument programs built from source, the +When Address Sanitizer is used to instrument programs built from source, the compiler first adds a dependency (`DT_NEEDED` entry) for the Address Sanitizer dynamic shared object (DSO). This shared object contains the main logic for Address Sanitizer, including setting and managing up the shadow memory. It also provides -replacement implementations for a number of functions in standard libraries. +replacement implementations for a number of functions in standard libraries. These replacements include things like `malloc` and `free` which allows for those allocations to be marked in the shadow memory, but also a number of other fuctions. -Consider `memcpy` for example, this is instrumented to validate the paramters -(test the source and destination buffers against the shadow memory. This is much -easier than instrumenting those standard libraries since, first it would require +Consider `memcpy` for example, this is instrumented to validate the paramters +(test the source and destination buffers against the shadow memory. This is much +easier than instrumenting those standard libraries since, first it would require you to re-compile them and secondly it would mean that the instrumentation would -be applied at a more expensive granular level. Lastly, load-widening (typically +be applied at a more expensive granular level. Lastly, load-widening (typically found in highy optimized code) can also make this instrumentation more difficult. Since the DSO is loaded before all of the standard libraries (in fact it insists @@ -165,9 +277,9 @@ modules which depend on it. FASAN takes a similar approach. It requires the user to add the Address Sanitizer DSO to the `AFL_PRELOAD` environment variable such that it is loaded into the target. -Again, it must be first in the list. This means that it is not necessary to -instrument the standard libraries to detect when an application has provided an -incorrect argument to `memcpy` for example. This avoids issues with load-widening +Again, it must be first in the list. This means that it is not necessary to +instrument the standard libraries to detect when an application has provided an +incorrect argument to `memcpy` for example. This avoids issues with load-widening and should also mean a huge improvement in performance. FASAN then adds instrumentation for any instrucutions which use memory operands and @@ -176,7 +288,7 @@ to validate memory accesses against the shadow memory. ## TODO -The next features to be added are Aarch64 and Aarch32 support as well as looking at +The next features to be added are Aarch64 and Aarch32 support as well as looking at potential performance improvements. The intention is to achieve feature parity with QEMU mode in due course. Contributions are welcome, but please get in touch to ensure that efforts are deconflicted. diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 03fd33e5..ed92c25a 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -19,5 +19,9 @@ gboolean instrument_is_coverage_optimize_supported(void); void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output); +void instrument_debug_init(void); +void instrument_debug_start(uint64_t address, GumStalkerOutput *output); +void instrument_debug_instruction(uint64_t address, uint16_t size); +void instrument_debug_end(GumStalkerOutput *output); #endif diff --git a/frida_mode/include/output.h b/frida_mode/include/output.h new file mode 100644 index 00000000..53a9fdd3 --- /dev/null +++ b/frida_mode/include/output.h @@ -0,0 +1,9 @@ +#ifndef _OUTPUT_H +#define _OUTPUT_H + +#include "frida-gum.h" + +void output_init(void); + +#endif + diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h index e58c5301..25b44ab0 100644 --- a/frida_mode/include/persistent.h +++ b/frida_mode/include/persistent.h @@ -18,6 +18,9 @@ extern unsigned char *__afl_fuzz_ptr; extern guint64 persistent_start; extern guint64 persistent_count; +extern guint64 persistent_ret; +extern guint64 persistent_ret_offset; +extern gboolean persistent_debug; extern afl_persistent_hook_fn hook; void persistent_init(void); @@ -26,6 +29,7 @@ void persistent_init(void); gboolean persistent_is_supported(void); void persistent_prologue(GumStalkerOutput *output); +void persistent_epilogue(GumStalkerOutput *output); #endif diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index f652eb8a..c623f473 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -7,5 +7,7 @@ void ranges_init(void); gboolean range_is_excluded(gpointer address); +void ranges_exclude(); + #endif diff --git a/frida_mode/include/stats.h b/frida_mode/include/stats.h new file mode 100644 index 00000000..4271132a --- /dev/null +++ b/frida_mode/include/stats.h @@ -0,0 +1,28 @@ +#ifndef _STATS_H +#define _STATS_H + +#include "frida-gum.h" + +typedef struct { + + guint64 num_blocks; + guint64 num_instructions; + guint64 stats_last_time; + guint64 stats_idx; + guint64 transitions_idx; + +} stats_data_header_t; + +extern stats_data_header_t *stats_data; + +void stats_init(void); +void stats_collect(const cs_insn *instr, gboolean begin); +void stats_print(char *format, ...); + +gboolean stats_is_supported_arch(void); +size_t stats_data_size_arch(void); +void stats_collect_arch(const cs_insn *instr); +void stats_write_arch(void); + +#endif + diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h index afd0b9c1..7b443b5e 100644 --- a/frida_mode/include/util.h +++ b/frida_mode/include/util.h @@ -4,7 +4,7 @@ #include "frida-gum.h" #define UNUSED_PARAMETER(x) (void)(x) -#define IGNORED_RERURN(x) (void)!(x) +#define IGNORED_RETURN(x) (void)!(x) guint64 util_read_address(char *key); diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 67eadc3f..cd1ac0be 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -13,6 +13,7 @@ #include "prefetch.h" #include "ranges.h" #include "stalker.h" +#include "stats.h" #include "util.h" static gboolean tracing = false; @@ -47,7 +48,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", current_pc, previous_pc); - IGNORED_RERURN(write(STDOUT_FILENO, buffer, len + 1)); + IGNORED_RETURN(write(STDOUT_FILENO, buffer, len + 1)); } @@ -79,17 +80,52 @@ static void instr_basic_block(GumStalkerIterator *iterator, const cs_insn *instr; gboolean begin = TRUE; + gboolean excluded; + while (gum_stalker_iterator_next(iterator, &instr)) { if (instr->address == entry_start) { entry_prologue(iterator, output); } if (instr->address == persistent_start) { persistent_prologue(output); } - - if (begin) { + if (instr->address == persistent_ret) { persistent_epilogue(output); } + + /* + * Until we reach AFL_ENTRYPOINT (assumed to be main if not specified) or + * AFL_FRIDA_PERSISTENT_ADDR (if specified), we don't mark our ranges + * excluded as we wish to remain inside stalker at all times so that we can + * instrument our entry point and persistent loop (if present). This allows + * the user to exclude ranges which would be traversed between main and the + * AFL_ENTRYPOINT, but which they don't want included in their coverage + * information when fuzzing. + * + * Since we have no means to discard the instrumented copies of blocks + * (setting the trust threshold simply causes a new copy to be made on each + * execution), we instead ensure that we honour the additional + * instrumentation requested (e.g. coverage, asan and complog) when a block + * is compiled no matter where we are during initialization. We will end up + * re-using these blocks if the code under test calls a block which is also + * used during initialization. + * + * Coverage data generated during initialization isn't a problem since the + * map is zeroed each time the target is forked or each time the persistent + * loop is run. + * + * Lastly, we don't enable pre-fetching back to the parent until we reach + * our AFL_ENTRYPOINT, since it is not until then that we start the + * fork-server and thus start executing in the child. + */ + excluded = range_is_excluded(GSIZE_TO_POINTER(instr->address)); + + stats_collect(instr, begin); + + if (unlikely(begin)) { + + instrument_debug_start(instr->address, output); prefetch_write(GSIZE_TO_POINTER(instr->address)); - if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) { - if (optimize) { + if (likely(!excluded)) { + + if (likely(optimize)) { instrument_coverage_optimize(instr, output); @@ -106,7 +142,9 @@ static void instr_basic_block(GumStalkerIterator *iterator, } - if (!range_is_excluded(GSIZE_TO_POINTER(instr->address))) { + instrument_debug_instruction(instr->address, instr->size); + + if (likely(!excluded)) { asan_instrument(instr, iterator); cmplog_instrument(instr, iterator); @@ -117,6 +155,8 @@ static void instr_basic_block(GumStalkerIterator *iterator, } + instrument_debug_end(output); + } void instrument_init(void) { @@ -144,6 +184,7 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + instrument_debug_init(); asan_init(); cmplog_init(); diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c new file mode 100644 index 00000000..be72ef89 --- /dev/null +++ b/frida_mode/src/instrument/instrument_debug.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include + +#include "frida-gum.h" + +#include "debug.h" + +#include "util.h" + +static int debugging_fd = -1; +static gpointer instrument_gen_start = NULL; + +static void instrument_debug(char *format, ...) { + + va_list ap; + char buffer[4096] = {0}; + int ret; + int len; + + va_start(ap, format); + ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); + va_end(ap); + + if (ret < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + + IGNORED_RETURN(write(debugging_fd, buffer, len)); + +} + +static void instrument_disasm(guint8 *code, guint size) { + + csh capstone; + cs_err err; + cs_insn *insn; + size_t count, i; + + err = cs_open(GUM_DEFAULT_CS_ARCH, + GUM_DEFAULT_CS_MODE | GUM_DEFAULT_CS_ENDIAN, &capstone); + g_assert(err == CS_ERR_OK); + + count = cs_disasm(capstone, code, size, GPOINTER_TO_SIZE(code), 0, &insn); + g_assert(insn != NULL); + + for (i = 0; i != count; i++) { + + instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t%s %s\n", insn[i].address, + insn[i].mnemonic, insn[i].op_str); + + } + + cs_free(insn, count); + + cs_close(&capstone); + +} + +static gpointer instrument_cur(GumStalkerOutput *output) { + +#if defined(__i386__) || defined(__x86_64__) + return gum_x86_writer_cur(output->writer.x86); +#elif defined(__aarch64__) + return gum_arm64_writer_cur(output->writer.arm64); +#elif defined(__arm__) + return gum_arm_writer_cur(output->writer.arm); +#else + #error "Unsupported architecture" +#endif + +} + +void instrument_debug_init(void) { + + char *filename = getenv("AFL_FRIDA_INST_DEBUG_FILE"); + OKF("Instrumentation debugging - enabled [%c]", filename == NULL ? ' ' : 'X'); + + if (filename == NULL) { return; } + + OKF("Instrumentation debugging - file [%s]", filename); + + if (filename == NULL) { return; } + + char *path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Instrumentation debugging - path [%s]", path); + + debugging_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (debugging_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + + g_free(path); + +} + +void instrument_debug_start(uint64_t address, GumStalkerOutput *output) { + + if (likely(debugging_fd < 0)) { return; } + + instrument_gen_start = instrument_cur(output); + + instrument_debug("\n\n***\n\nCreating block for 0x%" G_GINT64_MODIFIER "x:\n", + address); + +} + +void instrument_debug_instruction(uint64_t address, uint16_t size) { + + if (likely(debugging_fd < 0)) { return; } + uint8_t *start = (uint8_t *)GSIZE_TO_POINTER(address); + instrument_disasm(start, size); + +} + +void instrument_debug_end(GumStalkerOutput *output) { + + if (likely(debugging_fd < 0)) { return; } + gpointer instrument_gen_end = instrument_cur(output); + uint16_t size = GPOINTER_TO_SIZE(instrument_gen_end) - + GPOINTER_TO_SIZE(instrument_gen_start); + + instrument_debug("\nGenerated block %p\n", instrument_gen_start); + instrument_disasm(instrument_gen_start, size); + +} + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 21073cbe..1ab9993f 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -1,3 +1,4 @@ +#include #include #include @@ -18,10 +19,12 @@ #include "instrument.h" #include "interceptor.h" #include "lib.h" +#include "output.h" #include "persistent.h" #include "prefetch.h" #include "ranges.h" #include "stalker.h" +#include "stats.h" #include "util.h" #ifdef __APPLE__ @@ -58,10 +61,10 @@ static void on_main_os(int argc, char **argv, char **envp) { static void on_main_os(int argc, char **argv, char **envp) { UNUSED_PARAMETER(argc); - /* Personality doesn't affect the current process, it only takes effect on * evec */ int persona = personality(ADDR_NO_RANDOMIZE); + if (persona == -1) { WARNF("Failed to set ADDR_NO_RANDOMIZE: %d", errno); } if ((persona & ADDR_NO_RANDOMIZE) == 0) { execvpe(argv[0], argv, envp); } GumInterceptor *interceptor = gum_interceptor_obtain(); @@ -94,9 +97,11 @@ void afl_frida_start() { lib_init(); entry_init(); instrument_init(); + output_init(); persistent_init(); prefetch_init(); ranges_init(); + stats_init(); void *fork_addr = GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); diff --git a/frida_mode/src/output.c b/frida_mode/src/output.c new file mode 100644 index 00000000..8a222b25 --- /dev/null +++ b/frida_mode/src/output.c @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "frida-gum.h" + +#include "debug.h" + +#include "output.h" + +static int output_fd = -1; + +static void output_redirect(int fd, char *variable) { + + char *filename = getenv(variable); + char *path = NULL; + + if (filename == NULL) { return; } + + path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Redirect %d -> '%s'", fd, path); + + output_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + g_free(path); + + if (output_fd < 0) { FATAL("Failed to open fd(%d) error %d", fd, errno); } + + if (dup2(output_fd, fd) < 0) { + + FATAL("Failed to set fd(%d) error %d", fd, errno); + + } + +} + +void output_init(void) { + + output_redirect(STDOUT_FILENO, "AFL_FRIDA_OUTPUT_STDOUT"); + output_redirect(STDERR_FILENO, "AFL_FRIDA_OUTPUT_STDERR"); + +} + diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index 918ff153..2ec5b9cc 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -12,6 +12,9 @@ int __afl_sharedmem_fuzzing = 0; afl_persistent_hook_fn hook = NULL; guint64 persistent_start = 0; guint64 persistent_count = 0; +guint64 persistent_ret = 0; +guint64 persistent_ret_offset = 0; +gboolean persistent_debug = FALSE; void persistent_init(void) { @@ -19,12 +22,36 @@ void persistent_init(void) { persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); + persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET"); + persistent_ret_offset = + util_read_address("AFL_FRIDA_PERSISTENT_RETADDR_OFFSET"); + + if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; } + + if (persistent_count != 0 && persistent_start == 0) { - if (persistent_count != 0 && persistent_start == 0) FATAL( "AFL_FRIDA_PERSISTENT_ADDR must be specified if " "AFL_FRIDA_PERSISTENT_CNT is"); + } + + if (persistent_ret != 0 && persistent_start == 0) { + + FATAL( + "AFL_FRIDA_PERSISTENT_ADDR must be specified if " + "AFL_FRIDA_PERSISTENT_RET is"); + + } + + if (persistent_ret_offset != 0 && persistent_ret == 0) { + + FATAL( + "AFL_FRIDA_PERSISTENT_RET must be specified if " + "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET is"); + + } + if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; if (persistent_count != 0 && persistent_count < 100) @@ -39,6 +66,11 @@ void persistent_init(void) { persistent_start == 0 ? ' ' : 'X', persistent_count); OKF("Instrumentation - hook [%s]", hook_name); + OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_ret == 0 ? ' ' : 'X', persistent_ret); + OKF("Instrumentation - persistent ret offset [%c] (%" G_GINT64_MODIFIER "d)", + persistent_ret_offset == 0 ? ' ' : 'X', persistent_ret_offset); + if (hook_name != NULL) { void *hook_obj = dlopen(hook_name, RTLD_NOW); diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c index bc021ff3..6a3c06fa 100644 --- a/frida_mode/src/persistent/persistent_arm32.c +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -68,5 +68,12 @@ void persistent_prologue(GumStalkerOutput *output) { } +void persistent_epilogue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + #endif diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c index c198da69..1215d8da 100644 --- a/frida_mode/src/persistent/persistent_arm64.c +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -111,5 +111,12 @@ void persistent_prologue(GumStalkerOutput *output) { } +void persistent_epilogue(GumStalkerOutput *output) { + + UNUSED_PARAMETER(output); + FATAL("Persistent mode not supported on this architecture"); + +} + #endif diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index aa772b7f..4c495d47 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -1,9 +1,11 @@ #include "frida-gum.h" #include "config.h" +#include "debug.h" #include "instrument.h" #include "persistent.h" +#include "util.h" #if defined(__x86_64__) @@ -264,7 +266,6 @@ void persistent_prologue(GumStalkerOutput *output) { GumX86Writer *cw = output->writer.x86; gconstpointer loop = cw->code + 1; - // gum_x86_writer_put_breakpoint(cw); /* Stack must be 16-byte aligned per ABI */ instrument_persitent_save_regs(cw, &saved_regs); @@ -288,7 +289,9 @@ void persistent_prologue(GumStalkerOutput *output) { instrument_persitent_restore_regs(cw, &saved_regs); gconstpointer original = cw->code + 1; /* call original */ + gum_x86_writer_put_call_near_label(cw, original); + /* jmp loop */ gum_x86_writer_put_jmp_near_label(cw, loop); @@ -300,9 +303,23 @@ void persistent_prologue(GumStalkerOutput *output) { /* original: */ gum_x86_writer_put_label(cw, original); + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + gum_x86_writer_flush(cw); } +void persistent_epilogue(GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + persistent_ret_offset); + gum_x86_writer_put_ret(cw); + +} + #endif diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 20a3dc42..b30dfadf 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -244,9 +244,24 @@ void persistent_prologue(GumStalkerOutput *output) { /* original: */ gum_x86_writer_put_label(cw, original); + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + gum_x86_writer_flush(cw); } +void persistent_epilogue(GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, + persistent_ret_offset); + + gum_x86_writer_put_ret(cw); + +} + #endif diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index e3f09f9e..ef25b371 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -480,15 +480,40 @@ static GArray *merge_ranges(GArray *a) { } +static gboolean exclude_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + gchar * name; + gboolean found; + GumStalker *stalker; + if (details->file == NULL) { return TRUE; } + name = g_path_get_basename(details->file->path); + + found = (g_strcmp0(name, "afl-frida-trace.so") == 0); + g_free(name); + if (!found) { return TRUE; } + + stalker = stalker_get(); + gum_stalker_exclude(stalker, details->range); + + return FALSE; + +} + +static void ranges_exclude_self(void) { + + gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, exclude_ranges_callback, NULL); + +} + void ranges_init(void) { - GumMemoryRange ri; - GArray * step1; - GArray * step2; - GArray * step3; - GArray * step4; - GumMemoryRange *r; - GumStalker * stalker; + GumMemoryRange ri; + GArray * step1; + GArray * step2; + GArray * step3; + GArray * step4; if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { @@ -535,20 +560,16 @@ void ranges_init(void) { ranges = merge_ranges(step4); print_ranges("final", ranges); - stalker = stalker_get(); - - for (guint i = 0; i < ranges->len; i++) { - - r = &g_array_index(ranges, GumMemoryRange, i); - gum_stalker_exclude(stalker, r); - - } - g_array_free(step4, TRUE); g_array_free(step3, TRUE); g_array_free(step2, TRUE); g_array_free(step1, TRUE); + /* *NEVER* stalk the stalker, only bad things will ever come of this! */ + ranges_exclude_self(); + + ranges_exclude(); + } gboolean range_is_excluded(gpointer address) { @@ -572,3 +593,19 @@ gboolean range_is_excluded(gpointer address) { } +void ranges_exclude() { + + GumMemoryRange *r; + GumStalker * stalker = stalker_get(); + + OKF("Excluding ranges"); + + for (guint i = 0; i < ranges->len; i++) { + + r = &g_array_index(ranges, GumMemoryRange, i); + gum_stalker_exclude(stalker, r); + + } + +} + diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c new file mode 100644 index 00000000..890a8d6b --- /dev/null +++ b/frida_mode/src/stats/stats.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include +#include + +#include "frida-gum.h" + +#include "config.h" +#include "debug.h" +#include "util.h" + +#include "stats.h" + +#define MICRO_TO_SEC 1000000 + +stats_data_header_t *stats_data = NULL; + +static int stats_parent_pid = -1; +static int stats_fd = -1; +static gboolean stats_transitions = FALSE; +static guint64 stats_interval = 0; + +void stats_init(void) { + + stats_parent_pid = getpid(); + char *filename = getenv("AFL_FRIDA_STATS_FILE"); + stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); + if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) { + + stats_transitions = TRUE; + + } + + OKF("Stats - file [%s]", filename); + OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); + + if (stats_interval != 0 && filename == NULL) { + + FATAL( + "AFL_FRIDA_STATS_FILE must be specified if " + "AFL_FRIDA_STATS_INTERVAL is"); + + } + + if (stats_interval == 0) { stats_interval = 10; } + + if (filename == NULL) { return; } + + if (!stats_is_supported_arch()) { + + FATAL("Stats is not supported on this architecture"); + + } + + char *path = NULL; + + if (filename == NULL) { return; } + + if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); } + + path = g_canonicalize_filename(filename, g_get_current_dir()); + + OKF("Stats - path [%s]", path); + + stats_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (stats_fd < 0) { FATAL("Failed to open stats file '%s'", path); } + + g_free(path); + + size_t data_size = stats_data_size_arch(); + + int shm_id = shmget(IPC_PRIVATE, data_size, IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + stats_data = shmat(shm_id, NULL, 0); + g_assert(stats_data != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + + FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); + + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(stats_data, '\0', data_size); + +} + +void stats_vprint(int fd, char *format, va_list ap) { + + char buffer[4096] = {0}; + int ret; + int len; + + if(vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + IGNORED_RETURN(write(fd, buffer, len)); + +} + +void stats_print_fd(int fd, char *format, ...) { + + va_list ap; + va_start(ap, format); + stats_vprint(fd, format, ap); + va_end(ap); + +} + +void stats_print(char *format, ...) { + + va_list ap; + va_start(ap, format); + stats_vprint(stats_fd, format, ap); + va_end(ap); + +} + +void stats_write(void) { + + if (stats_parent_pid == getpid()) { return; } + + GDateTime *date_time = g_date_time_new_now_local(); + char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + + stats_print("stats\n"); + stats_print("-----\n"); + + stats_print("Index: %" G_GINT64_MODIFIER "u\n", + stats_data->stats_idx++); + stats_print("Pid: %d\n", getpid()); + stats_print("Time: %s\n", date_time_string); + stats_print("Blocks: %" G_GINT64_MODIFIER "u\n", + stats_data->num_blocks); + stats_print("Instructions: %" G_GINT64_MODIFIER "u\n", + stats_data->num_instructions); + stats_print("Avg Instructions / Block: %" G_GINT64_MODIFIER "u\n", + stats_data->num_instructions / stats_data->num_blocks); + + stats_print("\n"); + + g_free(date_time_string); + g_date_time_unref(date_time); + + stats_write_arch(); + + if (stats_transitions) { + + GDateTime *date_time = g_date_time_new_now_local(); + char *date_time_string = g_date_time_format(date_time, "%Y-%m-%e %H:%M:%S"); + + stats_print_fd(STDERR_FILENO, "stats\n"); + stats_print_fd(STDERR_FILENO, "-----\n"); + stats_print_fd(STDERR_FILENO, "Index: %" G_GINT64_MODIFIER "u\n", + stats_data->transitions_idx++); + stats_print_fd(STDERR_FILENO, "Pid: %d\n", getpid()); + stats_print_fd(STDERR_FILENO, "Time: %s\n", date_time_string); + + g_free(date_time_string); + g_date_time_unref(date_time); + gum_stalker_dump_counters(); + + } + +} + +static void stats_maybe_write(void) { + + guint64 current_time; + + if (stats_interval == 0) { return; } + + current_time = g_get_monotonic_time(); + + if ((current_time - stats_data->stats_last_time) > + (stats_interval * MICRO_TO_SEC)) { + + stats_write(); + stats_data->stats_last_time = current_time; + + } + +} + +void stats_collect(const cs_insn *instr, gboolean begin) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(begin); + + if (stats_fd < 0) { return; } + + if (begin) { stats_data->num_blocks++; } + stats_data->num_instructions++; + + stats_collect_arch(instr); + + stats_maybe_write(); + +} + diff --git a/frida_mode/src/stats/stats_arm.c b/frida_mode/src/stats/stats_arm.c new file mode 100644 index 00000000..7eea7f91 --- /dev/null +++ b/frida_mode/src/stats/stats_arm.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__arm__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c new file mode 100644 index 00000000..592af87a --- /dev/null +++ b/frida_mode/src/stats/stats_arm64.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__aarch64__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/stats/stats_x64.c b/frida_mode/src/stats/stats_x64.c new file mode 100644 index 00000000..c3e8742a --- /dev/null +++ b/frida_mode/src/stats/stats_x64.c @@ -0,0 +1,307 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ranges.h" +#include "stats.h" +#include "util.h" + +#if defined(__x86_64__) + +typedef struct { + + stats_data_header_t header; + + guint64 num_call_imm; + guint64 num_call_imm_excluded; + guint64 num_call_reg; + guint64 num_call_mem; + + guint64 num_jmp_imm; + guint64 num_jmp_reg; + guint64 num_jmp_mem; + + guint64 num_jmp_cond_imm; + guint64 num_jmp_cond_reg; + guint64 num_jmp_cond_mem; + + guint64 num_jmp_cond_jcxz; + + guint64 num_ret; + + guint64 num_rip_relative; + +} stats_data_arch_t; + +gboolean stats_is_supported_arch(void) { + + return TRUE; + +} + +size_t stats_data_size_arch(void) { + + return sizeof(stats_data_arch_t); + +} + +void stats_write_arch(void) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + guint64 num_instructions = stats_data_arch->header.num_instructions; + + stats_print( + "Call Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_imm, + ((float)(stats_data_arch->num_call_imm * 100) / num_instructions)); + stats_print("Call Immediates Excluded: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_imm_excluded, + ((float)(stats_data_arch->num_call_imm_excluded * 100) / + num_instructions)); + stats_print( + "Call Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_reg, + ((float)(stats_data_arch->num_call_reg * 100) / num_instructions)); + stats_print( + "Call Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_call_mem, + ((float)(stats_data_arch->num_call_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print("Jump Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_imm, + ((float)(stats_data_arch->num_jmp_imm * 100) / num_instructions)); + stats_print("Jump Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_reg, + ((float)(stats_data_arch->num_jmp_reg * 100) / num_instructions)); + stats_print("Jump Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_mem, + ((float)(stats_data_arch->num_jmp_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print( + "Conditional Jump Immediates: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_imm, + ((float)(stats_data_arch->num_jmp_cond_imm * 100) / num_instructions)); + stats_print( + "Conditional Jump CX Immediate: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_jcxz, + ((float)(stats_data_arch->num_jmp_cond_jcxz * 100) / num_instructions)); + stats_print( + "Conditional Jump Register: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_reg, + ((float)(stats_data_arch->num_jmp_cond_reg * 100) / num_instructions)); + stats_print( + "Conditional Jump Memory: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_jmp_cond_mem, + ((float)(stats_data_arch->num_jmp_cond_mem * 100) / num_instructions)); + + stats_print("\n"); + + stats_print("Returns: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_ret, + (stats_data_arch->num_ret * 100 / num_instructions)); + + stats_print("\n"); + + stats_print("Rip Relative: %" G_GINT64_MODIFIER + "u " + "(%3.2f%%)\n", + stats_data_arch->num_rip_relative, + (stats_data_arch->num_rip_relative * 100 / num_instructions)); + + stats_print("\n"); + stats_print("\n"); + +} + +static x86_op_type stats_get_operand_type(const cs_insn *instr) { + + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op *operand; + + if (x86->op_count != 1) { + + FATAL("Unexpected operand count (%d): %s %s\n", x86->op_count, + instr->mnemonic, instr->op_str); + + } + + operand = &x86->operands[0]; + + return operand->type; + +} + +static void stats_collect_call_imm_excluded_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + cs_x86 * x86 = &instr->detail->x86; + cs_x86_op * operand = &x86->operands[0]; + + if (range_is_excluded((gpointer)operand->imm)) { + + stats_data_arch->num_call_imm_excluded++; + + } + +} + +static void stats_collect_call_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_call_imm++; + stats_collect_call_imm_excluded_arch(instr); + break; + case X86_OP_REG: + stats_data_arch->num_call_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_call_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_jump_cond_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + x86_op_type type = stats_get_operand_type(instr); + switch (type) { + + case X86_OP_IMM: + stats_data_arch->num_jmp_cond_imm++; + break; + case X86_OP_REG: + stats_data_arch->num_jmp_cond_reg++; + break; + case X86_OP_MEM: + stats_data_arch->num_jmp_cond_mem++; + break; + default: + FATAL("Invalid operand type: %s %s\n", instr->mnemonic, instr->op_str); + + } + +} + +static void stats_collect_rip_relative_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + cs_x86 * x86 = &instr->detail->x86; + guint mod; + guint rm; + + if (x86->encoding.modrm_offset == 0) { return; } + + mod = (x86->modrm & 0xc0) >> 6; + if (mod != 0) { return; } + + rm = (x86->modrm & 0x07) >> 0; + if (rm != 5) { return; } + + stats_data_arch->num_rip_relative++; + +} + +void stats_collect_arch(const cs_insn *instr) { + + stats_data_arch_t *stats_data_arch = (stats_data_arch_t *)stats_data; + switch (instr->id) { + + case X86_INS_CALL: + stats_collect_call_arch(instr); + break; + case X86_INS_JMP: + stats_collect_jump_arch(instr); + break; + case X86_INS_JA: + case X86_INS_JAE: + case X86_INS_JB: + case X86_INS_JBE: + case X86_INS_JE: + case X86_INS_JG: + case X86_INS_JGE: + case X86_INS_JL: + case X86_INS_JLE: + case X86_INS_JNE: + case X86_INS_JNO: + case X86_INS_JNP: + case X86_INS_JNS: + case X86_INS_JO: + case X86_INS_JP: + case X86_INS_JS: + stats_collect_jump_cond_arch(instr); + break; + case X86_INS_JECXZ: + case X86_INS_JRCXZ: + stats_data_arch->num_jmp_cond_jcxz++; + break; + case X86_INS_RET: + stats_data_arch->num_ret++; + break; + default: + stats_collect_rip_relative_arch(instr); + break; + + } + +} + +#endif + diff --git a/frida_mode/src/stats/stats_x86.c b/frida_mode/src/stats/stats_x86.c new file mode 100644 index 00000000..1906e809 --- /dev/null +++ b/frida_mode/src/stats/stats_x86.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__i386__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c index 86b94970..09e8a58b 100644 --- a/frida_mode/src/util.c +++ b/frida_mode/src/util.c @@ -10,7 +10,7 @@ guint64 util_read_address(char *key) { if (!g_str_has_prefix(value_str, "0x")) { - FATAL("Invalid address should have 0x prefix: %s\n", value_str); + FATAL("Invalid address should have 0x prefix: %s=%s\n", key, value_str); } @@ -20,8 +20,8 @@ guint64 util_read_address(char *key) { if (!g_ascii_isxdigit(*c)) { - FATAL("Invalid address not formed of hex digits: %s ('%c')\n", value_str, - *c); + FATAL("Invalid address not formed of hex digits: %s=%s ('%c')\n", key, + value_str, *c); } @@ -30,7 +30,7 @@ guint64 util_read_address(char *key) { guint64 value = g_ascii_strtoull(value_str2, NULL, 16); if (value == 0) { - FATAL("Invalid address failed hex conversion: %s\n", value_str2); + FATAL("Invalid address failed hex conversion: %s=%s\n", key, value_str2); } @@ -48,7 +48,8 @@ guint64 util_read_num(char *key) { if (!g_ascii_isdigit(*c)) { - FATAL("Invalid address not formed of decimal digits: %s\n", value_str); + FATAL("Invalid address not formed of decimal digits: %s=%s\n", key, + value_str); } @@ -57,7 +58,7 @@ guint64 util_read_num(char *key) { guint64 value = g_ascii_strtoull(value_str, NULL, 10); if (value == 0) { - FATAL("Invalid address failed numeric conversion: %s\n", value_str); + FATAL("Invalid address failed numeric conversion: %s=%s\n", key, value_str); } diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile new file mode 100644 index 00000000..c268ef66 --- /dev/null +++ b/frida_mode/test/deferred/GNUmakefile @@ -0,0 +1,71 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) +endif + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_ENTRYPOINT=$(AFL_ENTRYPOINT) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/deferred/Makefile b/frida_mode/test/deferred/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/deferred/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/deferred/testinstr.c b/frida_mode/test/deferred/testinstr.c new file mode 100644 index 00000000..8b3688d7 --- /dev/null +++ b/frida_mode/test/deferred/testinstr.c @@ -0,0 +1,125 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + + usleep(100000); + +} + +TESTINSTR_SECTION int do_run(char * file) { + return run(file); +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return do_run(argv[1]); + +} + diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile new file mode 100644 index 00000000..e30f2049 --- /dev/null +++ b/frida_mode/test/libpcap/GNUmakefile @@ -0,0 +1,188 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBPCAP_BUILD_DIR:=$(BUILD_DIR)libpcap/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PCAPTEST_BUILD_DIR:=$(BUILD_DIR)libpcaptest/ +TCPDUMP_BUILD_DIR:=$(BUILD_DIR)tcpdump/ + +LIBPCAP_PATCH_URL:=https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libpcap_fuzz_both/patch.diff +LIBPCAP_PATCH_FILE:=$(LIBPCAP_BUILD_DIR)patch.diff +LIBPCAP_URL:=https://github.com/the-tcpdump-group/libpcap.git +LIBPCAP_DIR:=$(LIBPCAP_BUILD_DIR)libpcap/ +LIBPCAP_CMAKEFILE:=$(LIBPCAP_DIR)CMakeLists.txt +LIBPCAP_MAKEFILE:=$(LIBPCAP_DIR)Makefile +LIBPCAP_LIB:=$(LIBPCAP_DIR)libpcap.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +PCAPTEST_SRC_DIR:=$(LIBPCAP_DIR)testprogs/fuzz/ +PCAPTEST_FILE:=$(PCAPTEST_SRC_DIR)fuzz_both.c +PCAPTEST_OBJ:=$(PCAPTEST_BUILD_DIR)fuzz_both.o + +TCPDUMP_URL:=https://github.com/the-tcpdump-group/tcpdump.git +TCPDUMP_TESTS_DIR:=$(TCPDUMP_BUILD_DIR)tests/ + +CFLAGS += -fpermissive + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +AFLPP_DRIVER_DUMMY_INPUT:=$(TCPDUMP_TESTS_DIR)in + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean qemu frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### PCAPTEST ######## + +$(PCAPTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PCAPTEST_FILE): | $(LIBPCAP_CMAKEFILE) + +$(PCAPTEST_OBJ): $(PCAPTEST_FILE) | $(PCAPTEST_BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -I $(LIBPCAP_DIR) -o $@ -c $< + +######### LIBPCAP ######## + +$(LIBPCAP_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPCAP_PATCH_FILE): | $(LIBPCAP_BUILD_DIR) + wget -O $@ $(LIBPCAP_PATCH_URL) + +$(LIBPCAP_CMAKEFILE): $(LIBPCAP_PATCH_FILE) | $(LIBPCAP_BUILD_DIR) + git clone --depth 1 $(LIBPCAP_URL) $(LIBPCAP_DIR) + git apply $(LIBPCAP_PATCH_FILE) + +$(LIBPCAP_MAKEFILE): $(LIBPCAP_CMAKEFILE) + cd $(LIBPCAP_DIR) && cmake . + +$(LIBPCAP_LIB): $(LIBPCAP_MAKEFILE) $(LIBPCAP_PATCH_FILE) + make -C $(LIBPCAP_DIR) + +######## TCPDUMP ###### + +$(TCPDUMP_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TCPDUMP_TESTS_DIR): | $(TCPDUMP_BUILD_DIR) + git clone --depth=1 $(TCPDUMP_URL) $(TCPDUMP_BUILD_DIR) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR) + truncate -s 1M $@ + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TCPDUMP_TESTS_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) | $(TCPDUMP_TESTS_DIR) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TCPDUMP_TESTS_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) diff --git a/frida_mode/test/libpcap/Makefile b/frida_mode/test/libpcap/Makefile new file mode 100644 index 00000000..31cacb67 --- /dev/null +++ b/frida_mode/test/libpcap/Makefile @@ -0,0 +1,1143 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.16 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap/build/libpcap/libpcap + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/jon/git/AFLplusplus/frida_mode/test/libpcap + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/jon/git/AFLplusplus/frida_mode/test/libpcap/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named pcap + +# Build rule for target. +pcap: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pcap +.PHONY : pcap + +# fast build rule for target. +pcap/fast: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/build +.PHONY : pcap/fast + +#============================================================================= +# Target rules for targets named uninstall + +# Build rule for target. +uninstall: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 uninstall +.PHONY : uninstall + +# fast build rule for target. +uninstall/fast: + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/build +.PHONY : uninstall/fast + +#============================================================================= +# Target rules for targets named pcap_static + +# Build rule for target. +pcap_static: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 pcap_static +.PHONY : pcap_static + +# fast build rule for target. +pcap_static/fast: + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/build +.PHONY : pcap_static/fast + +#============================================================================= +# Target rules for targets named SerializeTarget + +# Build rule for target. +SerializeTarget: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 SerializeTarget +.PHONY : SerializeTarget + +# fast build rule for target. +SerializeTarget/fast: + $(MAKE) -f CMakeFiles/SerializeTarget.dir/build.make CMakeFiles/SerializeTarget.dir/build +.PHONY : SerializeTarget/fast + +#============================================================================= +# Target rules for targets named testprogs + +# Build rule for target. +testprogs: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 testprogs +.PHONY : testprogs + +# fast build rule for target. +testprogs/fast: + $(MAKE) -f testprogs/CMakeFiles/testprogs.dir/build.make testprogs/CMakeFiles/testprogs.dir/build +.PHONY : testprogs/fast + +#============================================================================= +# Target rules for targets named capturetest + +# Build rule for target. +capturetest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 capturetest +.PHONY : capturetest + +# fast build rule for target. +capturetest/fast: + $(MAKE) -f testprogs/CMakeFiles/capturetest.dir/build.make testprogs/CMakeFiles/capturetest.dir/build +.PHONY : capturetest/fast + +#============================================================================= +# Target rules for targets named findalldevstest + +# Build rule for target. +findalldevstest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 findalldevstest +.PHONY : findalldevstest + +# fast build rule for target. +findalldevstest/fast: + $(MAKE) -f testprogs/CMakeFiles/findalldevstest.dir/build.make testprogs/CMakeFiles/findalldevstest.dir/build +.PHONY : findalldevstest/fast + +#============================================================================= +# Target rules for targets named filtertest + +# Build rule for target. +filtertest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 filtertest +.PHONY : filtertest + +# fast build rule for target. +filtertest/fast: + $(MAKE) -f testprogs/CMakeFiles/filtertest.dir/build.make testprogs/CMakeFiles/filtertest.dir/build +.PHONY : filtertest/fast + +#============================================================================= +# Target rules for targets named findalldevstest-perf + +# Build rule for target. +findalldevstest-perf: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 findalldevstest-perf +.PHONY : findalldevstest-perf + +# fast build rule for target. +findalldevstest-perf/fast: + $(MAKE) -f testprogs/CMakeFiles/findalldevstest-perf.dir/build.make testprogs/CMakeFiles/findalldevstest-perf.dir/build +.PHONY : findalldevstest-perf/fast + +#============================================================================= +# Target rules for targets named can_set_rfmon_test + +# Build rule for target. +can_set_rfmon_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 can_set_rfmon_test +.PHONY : can_set_rfmon_test + +# fast build rule for target. +can_set_rfmon_test/fast: + $(MAKE) -f testprogs/CMakeFiles/can_set_rfmon_test.dir/build.make testprogs/CMakeFiles/can_set_rfmon_test.dir/build +.PHONY : can_set_rfmon_test/fast + +#============================================================================= +# Target rules for targets named opentest + +# Build rule for target. +opentest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 opentest +.PHONY : opentest + +# fast build rule for target. +opentest/fast: + $(MAKE) -f testprogs/CMakeFiles/opentest.dir/build.make testprogs/CMakeFiles/opentest.dir/build +.PHONY : opentest/fast + +#============================================================================= +# Target rules for targets named reactivatetest + +# Build rule for target. +reactivatetest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 reactivatetest +.PHONY : reactivatetest + +# fast build rule for target. +reactivatetest/fast: + $(MAKE) -f testprogs/CMakeFiles/reactivatetest.dir/build.make testprogs/CMakeFiles/reactivatetest.dir/build +.PHONY : reactivatetest/fast + +#============================================================================= +# Target rules for targets named writecaptest + +# Build rule for target. +writecaptest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 writecaptest +.PHONY : writecaptest + +# fast build rule for target. +writecaptest/fast: + $(MAKE) -f testprogs/CMakeFiles/writecaptest.dir/build.make testprogs/CMakeFiles/writecaptest.dir/build +.PHONY : writecaptest/fast + +#============================================================================= +# Target rules for targets named selpolltest + +# Build rule for target. +selpolltest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 selpolltest +.PHONY : selpolltest + +# fast build rule for target. +selpolltest/fast: + $(MAKE) -f testprogs/CMakeFiles/selpolltest.dir/build.make testprogs/CMakeFiles/selpolltest.dir/build +.PHONY : selpolltest/fast + +#============================================================================= +# Target rules for targets named threadsignaltest + +# Build rule for target. +threadsignaltest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 threadsignaltest +.PHONY : threadsignaltest + +# fast build rule for target. +threadsignaltest/fast: + $(MAKE) -f testprogs/CMakeFiles/threadsignaltest.dir/build.make testprogs/CMakeFiles/threadsignaltest.dir/build +.PHONY : threadsignaltest/fast + +#============================================================================= +# Target rules for targets named valgrindtest + +# Build rule for target. +valgrindtest: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 valgrindtest +.PHONY : valgrindtest + +# fast build rule for target. +valgrindtest/fast: + $(MAKE) -f testprogs/CMakeFiles/valgrindtest.dir/build.make testprogs/CMakeFiles/valgrindtest.dir/build +.PHONY : valgrindtest/fast + +#============================================================================= +# Target rules for targets named fuzz_both + +# Build rule for target. +fuzz_both: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_both +.PHONY : fuzz_both + +# fast build rule for target. +fuzz_both/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_both.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_both.dir/build +.PHONY : fuzz_both/fast + +#============================================================================= +# Target rules for targets named fuzz_filter + +# Build rule for target. +fuzz_filter: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_filter +.PHONY : fuzz_filter + +# fast build rule for target. +fuzz_filter/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_filter.dir/build +.PHONY : fuzz_filter/fast + +#============================================================================= +# Target rules for targets named fuzz_pcap + +# Build rule for target. +fuzz_pcap: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 fuzz_pcap +.PHONY : fuzz_pcap + +# fast build rule for target. +fuzz_pcap/fast: + $(MAKE) -f testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build.make testprogs/fuzz/CMakeFiles/fuzz_pcap.dir/build +.PHONY : fuzz_pcap/fast + +bpf_dump.o: bpf_dump.c.o + +.PHONY : bpf_dump.o + +# target to build an object file +bpf_dump.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.o +.PHONY : bpf_dump.c.o + +bpf_dump.i: bpf_dump.c.i + +.PHONY : bpf_dump.i + +# target to preprocess a source file +bpf_dump.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.i +.PHONY : bpf_dump.c.i + +bpf_dump.s: bpf_dump.c.s + +.PHONY : bpf_dump.s + +# target to generate assembly for a file +bpf_dump.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_dump.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_dump.c.s +.PHONY : bpf_dump.c.s + +bpf_filter.o: bpf_filter.c.o + +.PHONY : bpf_filter.o + +# target to build an object file +bpf_filter.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.o +.PHONY : bpf_filter.c.o + +bpf_filter.i: bpf_filter.c.i + +.PHONY : bpf_filter.i + +# target to preprocess a source file +bpf_filter.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.i +.PHONY : bpf_filter.c.i + +bpf_filter.s: bpf_filter.c.s + +.PHONY : bpf_filter.s + +# target to generate assembly for a file +bpf_filter.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_filter.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_filter.c.s +.PHONY : bpf_filter.c.s + +bpf_image.o: bpf_image.c.o + +.PHONY : bpf_image.o + +# target to build an object file +bpf_image.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.o +.PHONY : bpf_image.c.o + +bpf_image.i: bpf_image.c.i + +.PHONY : bpf_image.i + +# target to preprocess a source file +bpf_image.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.i +.PHONY : bpf_image.c.i + +bpf_image.s: bpf_image.c.s + +.PHONY : bpf_image.s + +# target to generate assembly for a file +bpf_image.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/bpf_image.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/bpf_image.c.s +.PHONY : bpf_image.c.s + +etherent.o: etherent.c.o + +.PHONY : etherent.o + +# target to build an object file +etherent.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.o +.PHONY : etherent.c.o + +etherent.i: etherent.c.i + +.PHONY : etherent.i + +# target to preprocess a source file +etherent.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.i +.PHONY : etherent.c.i + +etherent.s: etherent.c.s + +.PHONY : etherent.s + +# target to generate assembly for a file +etherent.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/etherent.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/etherent.c.s +.PHONY : etherent.c.s + +fad-getad.o: fad-getad.c.o + +.PHONY : fad-getad.o + +# target to build an object file +fad-getad.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.o +.PHONY : fad-getad.c.o + +fad-getad.i: fad-getad.c.i + +.PHONY : fad-getad.i + +# target to preprocess a source file +fad-getad.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.i +.PHONY : fad-getad.c.i + +fad-getad.s: fad-getad.c.s + +.PHONY : fad-getad.s + +# target to generate assembly for a file +fad-getad.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fad-getad.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fad-getad.c.s +.PHONY : fad-getad.c.s + +fmtutils.o: fmtutils.c.o + +.PHONY : fmtutils.o + +# target to build an object file +fmtutils.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.o +.PHONY : fmtutils.c.o + +fmtutils.i: fmtutils.c.i + +.PHONY : fmtutils.i + +# target to preprocess a source file +fmtutils.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.i +.PHONY : fmtutils.c.i + +fmtutils.s: fmtutils.c.s + +.PHONY : fmtutils.s + +# target to generate assembly for a file +fmtutils.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/fmtutils.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/fmtutils.c.s +.PHONY : fmtutils.c.s + +gencode.o: gencode.c.o + +.PHONY : gencode.o + +# target to build an object file +gencode.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.o +.PHONY : gencode.c.o + +gencode.i: gencode.c.i + +.PHONY : gencode.i + +# target to preprocess a source file +gencode.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.i +.PHONY : gencode.c.i + +gencode.s: gencode.c.s + +.PHONY : gencode.s + +# target to generate assembly for a file +gencode.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/gencode.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/gencode.c.s +.PHONY : gencode.c.s + +grammar.o: grammar.c.o + +.PHONY : grammar.o + +# target to build an object file +grammar.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.o +.PHONY : grammar.c.o + +grammar.i: grammar.c.i + +.PHONY : grammar.i + +# target to preprocess a source file +grammar.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.i +.PHONY : grammar.c.i + +grammar.s: grammar.c.s + +.PHONY : grammar.s + +# target to generate assembly for a file +grammar.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/grammar.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/grammar.c.s +.PHONY : grammar.c.s + +missing/strlcat.o: missing/strlcat.c.o + +.PHONY : missing/strlcat.o + +# target to build an object file +missing/strlcat.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.o +.PHONY : missing/strlcat.c.o + +missing/strlcat.i: missing/strlcat.c.i + +.PHONY : missing/strlcat.i + +# target to preprocess a source file +missing/strlcat.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.i +.PHONY : missing/strlcat.c.i + +missing/strlcat.s: missing/strlcat.c.s + +.PHONY : missing/strlcat.s + +# target to generate assembly for a file +missing/strlcat.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcat.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcat.c.s +.PHONY : missing/strlcat.c.s + +missing/strlcpy.o: missing/strlcpy.c.o + +.PHONY : missing/strlcpy.o + +# target to build an object file +missing/strlcpy.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.o +.PHONY : missing/strlcpy.c.o + +missing/strlcpy.i: missing/strlcpy.c.i + +.PHONY : missing/strlcpy.i + +# target to preprocess a source file +missing/strlcpy.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.i +.PHONY : missing/strlcpy.c.i + +missing/strlcpy.s: missing/strlcpy.c.s + +.PHONY : missing/strlcpy.s + +# target to generate assembly for a file +missing/strlcpy.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/missing/strlcpy.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/missing/strlcpy.c.s +.PHONY : missing/strlcpy.c.s + +nametoaddr.o: nametoaddr.c.o + +.PHONY : nametoaddr.o + +# target to build an object file +nametoaddr.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.o +.PHONY : nametoaddr.c.o + +nametoaddr.i: nametoaddr.c.i + +.PHONY : nametoaddr.i + +# target to preprocess a source file +nametoaddr.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.i +.PHONY : nametoaddr.c.i + +nametoaddr.s: nametoaddr.c.s + +.PHONY : nametoaddr.s + +# target to generate assembly for a file +nametoaddr.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/nametoaddr.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/nametoaddr.c.s +.PHONY : nametoaddr.c.s + +optimize.o: optimize.c.o + +.PHONY : optimize.o + +# target to build an object file +optimize.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.o +.PHONY : optimize.c.o + +optimize.i: optimize.c.i + +.PHONY : optimize.i + +# target to preprocess a source file +optimize.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.i +.PHONY : optimize.c.i + +optimize.s: optimize.c.s + +.PHONY : optimize.s + +# target to generate assembly for a file +optimize.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/optimize.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/optimize.c.s +.PHONY : optimize.c.s + +pcap-common.o: pcap-common.c.o + +.PHONY : pcap-common.o + +# target to build an object file +pcap-common.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.o +.PHONY : pcap-common.c.o + +pcap-common.i: pcap-common.c.i + +.PHONY : pcap-common.i + +# target to preprocess a source file +pcap-common.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.i +.PHONY : pcap-common.c.i + +pcap-common.s: pcap-common.c.s + +.PHONY : pcap-common.s + +# target to generate assembly for a file +pcap-common.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-common.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-common.c.s +.PHONY : pcap-common.c.s + +pcap-linux.o: pcap-linux.c.o + +.PHONY : pcap-linux.o + +# target to build an object file +pcap-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.o +.PHONY : pcap-linux.c.o + +pcap-linux.i: pcap-linux.c.i + +.PHONY : pcap-linux.i + +# target to preprocess a source file +pcap-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.i +.PHONY : pcap-linux.c.i + +pcap-linux.s: pcap-linux.c.s + +.PHONY : pcap-linux.s + +# target to generate assembly for a file +pcap-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-linux.c.s +.PHONY : pcap-linux.c.s + +pcap-netfilter-linux.o: pcap-netfilter-linux.c.o + +.PHONY : pcap-netfilter-linux.o + +# target to build an object file +pcap-netfilter-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.o +.PHONY : pcap-netfilter-linux.c.o + +pcap-netfilter-linux.i: pcap-netfilter-linux.c.i + +.PHONY : pcap-netfilter-linux.i + +# target to preprocess a source file +pcap-netfilter-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.i +.PHONY : pcap-netfilter-linux.c.i + +pcap-netfilter-linux.s: pcap-netfilter-linux.c.s + +.PHONY : pcap-netfilter-linux.s + +# target to generate assembly for a file +pcap-netfilter-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-netfilter-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-netfilter-linux.c.s +.PHONY : pcap-netfilter-linux.c.s + +pcap-usb-linux.o: pcap-usb-linux.c.o + +.PHONY : pcap-usb-linux.o + +# target to build an object file +pcap-usb-linux.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.o +.PHONY : pcap-usb-linux.c.o + +pcap-usb-linux.i: pcap-usb-linux.c.i + +.PHONY : pcap-usb-linux.i + +# target to preprocess a source file +pcap-usb-linux.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.i +.PHONY : pcap-usb-linux.c.i + +pcap-usb-linux.s: pcap-usb-linux.c.s + +.PHONY : pcap-usb-linux.s + +# target to generate assembly for a file +pcap-usb-linux.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap-usb-linux.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap-usb-linux.c.s +.PHONY : pcap-usb-linux.c.s + +pcap.o: pcap.c.o + +.PHONY : pcap.o + +# target to build an object file +pcap.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.o +.PHONY : pcap.c.o + +pcap.i: pcap.c.i + +.PHONY : pcap.i + +# target to preprocess a source file +pcap.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.i +.PHONY : pcap.c.i + +pcap.s: pcap.c.s + +.PHONY : pcap.s + +# target to generate assembly for a file +pcap.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/pcap.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/pcap.c.s +.PHONY : pcap.c.s + +savefile.o: savefile.c.o + +.PHONY : savefile.o + +# target to build an object file +savefile.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.o +.PHONY : savefile.c.o + +savefile.i: savefile.c.i + +.PHONY : savefile.i + +# target to preprocess a source file +savefile.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.i +.PHONY : savefile.c.i + +savefile.s: savefile.c.s + +.PHONY : savefile.s + +# target to generate assembly for a file +savefile.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/savefile.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/savefile.c.s +.PHONY : savefile.c.s + +scanner.o: scanner.c.o + +.PHONY : scanner.o + +# target to build an object file +scanner.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.o +.PHONY : scanner.c.o + +scanner.i: scanner.c.i + +.PHONY : scanner.i + +# target to preprocess a source file +scanner.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.i +.PHONY : scanner.c.i + +scanner.s: scanner.c.s + +.PHONY : scanner.s + +# target to generate assembly for a file +scanner.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/scanner.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/scanner.c.s +.PHONY : scanner.c.s + +sf-pcap.o: sf-pcap.c.o + +.PHONY : sf-pcap.o + +# target to build an object file +sf-pcap.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.o +.PHONY : sf-pcap.c.o + +sf-pcap.i: sf-pcap.c.i + +.PHONY : sf-pcap.i + +# target to preprocess a source file +sf-pcap.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.i +.PHONY : sf-pcap.c.i + +sf-pcap.s: sf-pcap.c.s + +.PHONY : sf-pcap.s + +# target to generate assembly for a file +sf-pcap.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcap.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcap.c.s +.PHONY : sf-pcap.c.s + +sf-pcapng.o: sf-pcapng.c.o + +.PHONY : sf-pcapng.o + +# target to build an object file +sf-pcapng.c.o: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.o + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.o +.PHONY : sf-pcapng.c.o + +sf-pcapng.i: sf-pcapng.c.i + +.PHONY : sf-pcapng.i + +# target to preprocess a source file +sf-pcapng.c.i: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.i + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.i +.PHONY : sf-pcapng.c.i + +sf-pcapng.s: sf-pcapng.c.s + +.PHONY : sf-pcapng.s + +# target to generate assembly for a file +sf-pcapng.c.s: + $(MAKE) -f CMakeFiles/pcap.dir/build.make CMakeFiles/pcap.dir/sf-pcapng.c.s + $(MAKE) -f CMakeFiles/pcap_static.dir/build.make CMakeFiles/pcap_static.dir/sf-pcapng.c.s +.PHONY : sf-pcapng.c.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... install/strip" + @echo "... install/local" + @echo "... install" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... edit_cache" + @echo "... pcap" + @echo "... uninstall" + @echo "... pcap_static" + @echo "... SerializeTarget" + @echo "... testprogs" + @echo "... capturetest" + @echo "... findalldevstest" + @echo "... filtertest" + @echo "... findalldevstest-perf" + @echo "... can_set_rfmon_test" + @echo "... opentest" + @echo "... reactivatetest" + @echo "... writecaptest" + @echo "... selpolltest" + @echo "... threadsignaltest" + @echo "... valgrindtest" + @echo "... fuzz_both" + @echo "... fuzz_filter" + @echo "... fuzz_pcap" + @echo "... bpf_dump.o" + @echo "... bpf_dump.i" + @echo "... bpf_dump.s" + @echo "... bpf_filter.o" + @echo "... bpf_filter.i" + @echo "... bpf_filter.s" + @echo "... bpf_image.o" + @echo "... bpf_image.i" + @echo "... bpf_image.s" + @echo "... etherent.o" + @echo "... etherent.i" + @echo "... etherent.s" + @echo "... fad-getad.o" + @echo "... fad-getad.i" + @echo "... fad-getad.s" + @echo "... fmtutils.o" + @echo "... fmtutils.i" + @echo "... fmtutils.s" + @echo "... gencode.o" + @echo "... gencode.i" + @echo "... gencode.s" + @echo "... grammar.o" + @echo "... grammar.i" + @echo "... grammar.s" + @echo "... missing/strlcat.o" + @echo "... missing/strlcat.i" + @echo "... missing/strlcat.s" + @echo "... missing/strlcpy.o" + @echo "... missing/strlcpy.i" + @echo "... missing/strlcpy.s" + @echo "... nametoaddr.o" + @echo "... nametoaddr.i" + @echo "... nametoaddr.s" + @echo "... optimize.o" + @echo "... optimize.i" + @echo "... optimize.s" + @echo "... pcap-common.o" + @echo "... pcap-common.i" + @echo "... pcap-common.s" + @echo "... pcap-linux.o" + @echo "... pcap-linux.i" + @echo "... pcap-linux.s" + @echo "... pcap-netfilter-linux.o" + @echo "... pcap-netfilter-linux.i" + @echo "... pcap-netfilter-linux.s" + @echo "... pcap-usb-linux.o" + @echo "... pcap-usb-linux.i" + @echo "... pcap-usb-linux.s" + @echo "... pcap.o" + @echo "... pcap.i" + @echo "... pcap.s" + @echo "... savefile.o" + @echo "... savefile.i" + @echo "... savefile.s" + @echo "... scanner.o" + @echo "... scanner.i" + @echo "... scanner.s" + @echo "... sf-pcap.o" + @echo "... sf-pcap.i" + @echo "... sf-pcap.s" + @echo "... sf-pcapng.o" + @echo "... sf-pcapng.i" + @echo "... sf-pcapng.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include +#include + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/libpcap/get_symbol_addr.py b/frida_mode/test/libpcap/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/libpcap/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/output/GNUmakefile b/frida_mode/test/output/GNUmakefile new file mode 100644 index 00000000..eaa1c4dc --- /dev/null +++ b/frida_mode/test/output/GNUmakefile @@ -0,0 +1,47 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_OUTPUT_STDOUT=frida_stdout.txt \ + AFL_FRIDA_OUTPUT_STDERR=frida_stderr.txt \ + AFL_FRIDA_STATS_FILE=frida_stats.txt \ + AFL_FRIDA_STATS_INTERVAL=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/output/Makefile b/frida_mode/test/output/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/output/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/output/frida_stderr.txt b/frida_mode/test/output/frida_stderr.txt new file mode 100644 index 00000000..103216cf --- /dev/null +++ b/frida_mode/test/output/frida_stderr.txt @@ -0,0 +1,2824 @@ + + +total_transitions: 9 + call_imms: 1 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 1 + jmp_mems: 2 + jmp_regs: 0 + + jmp_cond_imms: 2 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 19 + call_imms: 4 + call_regs: 0 + call_mems: 0 + post_call_invokes: 2 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 1 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 6 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 29 + call_imms: 6 + call_regs: 1 + call_mems: 0 + post_call_invokes: 3 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 11 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 39 + call_imms: 6 + call_regs: 2 + call_mems: 0 + post_call_invokes: 5 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 18 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 49 + call_imms: 7 + call_regs: 2 + call_mems: 1 + post_call_invokes: 6 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 2 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 25 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 59 + call_imms: 8 + call_regs: 2 + call_mems: 3 + post_call_invokes: 6 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 3 + jmp_mems: 3 + jmp_regs: 0 + + jmp_cond_imms: 31 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 69 + call_imms: 9 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 3 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 38 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 79 + call_imms: 10 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 46 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 89 + call_imms: 10 + call_regs: 2 + call_mems: 3 + post_call_invokes: 7 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 56 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 99 + call_imms: 11 + call_regs: 2 + call_mems: 3 + post_call_invokes: 9 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 4 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 63 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 109 + call_imms: 12 + call_regs: 2 + call_mems: 3 + post_call_invokes: 12 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 5 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 68 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 119 + call_imms: 12 + call_regs: 2 + call_mems: 4 + post_call_invokes: 14 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 74 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 129 + call_imms: 14 + call_regs: 2 + call_mems: 4 + post_call_invokes: 16 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 4 + jmp_regs: 0 + + jmp_cond_imms: 80 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 139 + call_imms: 14 + call_regs: 2 + call_mems: 5 + post_call_invokes: 17 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 87 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 149 + call_imms: 14 + call_regs: 2 + call_mems: 6 + post_call_invokes: 17 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 6 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 96 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 159 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 18 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 8 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 102 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 170 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 18 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 10 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 111 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 180 + call_imms: 15 + call_regs: 2 + call_mems: 6 + post_call_invokes: 20 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 11 + jmp_mems: 5 + jmp_regs: 0 + + jmp_cond_imms: 118 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 190 + call_imms: 16 + call_regs: 2 + call_mems: 6 + post_call_invokes: 20 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 11 + jmp_mems: 6 + jmp_regs: 1 + + jmp_cond_imms: 125 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 201 + call_imms: 16 + call_regs: 2 + call_mems: 7 + post_call_invokes: 21 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 13 + jmp_mems: 6 + jmp_regs: 1 + + jmp_cond_imms: 132 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 211 + call_imms: 17 + call_regs: 2 + call_mems: 7 + post_call_invokes: 22 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 14 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 138 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 223 + call_imms: 18 + call_regs: 2 + call_mems: 8 + post_call_invokes: 24 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 15 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 145 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 233 + call_imms: 18 + call_regs: 2 + call_mems: 8 + post_call_invokes: 25 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 16 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 153 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 244 + call_imms: 19 + call_regs: 2 + call_mems: 9 + post_call_invokes: 26 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 16 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 161 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input + + +total_transitions: 254 + call_imms: 20 + call_regs: 2 + call_mems: 9 + post_call_invokes: 27 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 18 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 167 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 264 + call_imms: 20 + call_regs: 2 + call_mems: 9 + post_call_invokes: 29 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 20 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 173 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 275 + call_imms: 21 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 22 + jmp_mems: 7 + jmp_regs: 1 + + jmp_cond_imms: 179 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 285 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 23 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 186 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 295 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 23 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 196 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 305 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 30 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 24 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 205 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 315 + call_imms: 22 + call_regs: 2 + call_mems: 10 + post_call_invokes: 31 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 26 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 212 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 326 + call_imms: 22 + call_regs: 3 + call_mems: 10 + post_call_invokes: 32 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 8 + jmp_regs: 1 + + jmp_cond_imms: 220 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 337 + call_imms: 23 + call_regs: 4 + call_mems: 10 + post_call_invokes: 36 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 9 + jmp_regs: 1 + + jmp_cond_imms: 224 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 348 + call_imms: 24 + call_regs: 4 + call_mems: 10 + post_call_invokes: 38 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 27 + jmp_mems: 10 + jmp_regs: 1 + + jmp_cond_imms: 231 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 362 + call_imms: 26 + call_regs: 4 + call_mems: 10 + post_call_invokes: 39 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 11 + jmp_regs: 1 + + jmp_cond_imms: 240 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 375 + call_imms: 27 + call_regs: 4 + call_mems: 10 + post_call_invokes: 40 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 12 + jmp_regs: 1 + + jmp_cond_imms: 250 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 387 + call_imms: 28 + call_regs: 4 + call_mems: 10 + post_call_invokes: 41 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 28 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 258 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 397 + call_imms: 29 + call_regs: 4 + call_mems: 10 + post_call_invokes: 42 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 30 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 264 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 407 + call_imms: 29 + call_regs: 4 + call_mems: 10 + post_call_invokes: 42 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 31 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 273 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 418 + call_imms: 29 + call_regs: 4 + call_mems: 11 + post_call_invokes: 43 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 32 + jmp_mems: 12 + jmp_regs: 3 + + jmp_cond_imms: 281 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) + + +total_transitions: 430 + call_imms: 32 + call_regs: 4 + call_mems: 11 + post_call_invokes: 45 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 33 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 286 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 441 + call_imms: 32 + call_regs: 4 + call_mems: 12 + post_call_invokes: 46 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 33 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 295 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) + + +total_transitions: 453 + call_imms: 33 + call_regs: 4 + call_mems: 12 + post_call_invokes: 49 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 34 + jmp_mems: 13 + jmp_regs: 3 + + jmp_cond_imms: 302 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 465 + call_imms: 35 + call_regs: 4 + call_mems: 12 + post_call_invokes: 50 + excluded_call_imms: 2 + ret_slow_paths: 1 + + jmp_imms: 35 + jmp_mems: 15 + jmp_regs: 3 + + jmp_cond_imms: 308 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 475 + call_imms: 38 + call_regs: 4 + call_mems: 12 + post_call_invokes: 51 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 35 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 310 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 485 + call_imms: 38 + call_regs: 5 + call_mems: 12 + post_call_invokes: 52 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 36 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 317 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 495 + call_imms: 38 + call_regs: 5 + call_mems: 13 + post_call_invokes: 52 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 38 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 324 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 506 + call_imms: 38 + call_regs: 5 + call_mems: 13 + post_call_invokes: 53 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 39 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 333 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 516 + call_imms: 40 + call_regs: 5 + call_mems: 13 + post_call_invokes: 53 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 40 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 340 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 526 + call_imms: 40 + call_regs: 5 + call_mems: 13 + post_call_invokes: 54 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 40 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 349 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 540 + call_imms: 42 + call_regs: 5 + call_mems: 13 + post_call_invokes: 55 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 42 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 358 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 552 + call_imms: 43 + call_regs: 5 + call_mems: 13 + post_call_invokes: 57 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 43 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 366 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 563 + call_imms: 43 + call_regs: 5 + call_mems: 14 + post_call_invokes: 58 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 43 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 375 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 573 + call_imms: 43 + call_regs: 5 + call_mems: 15 + post_call_invokes: 59 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 44 + jmp_mems: 16 + jmp_regs: 3 + + jmp_cond_imms: 382 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 583 + call_imms: 44 + call_regs: 5 + call_mems: 15 + post_call_invokes: 59 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 45 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 389 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 593 + call_imms: 45 + call_regs: 5 + call_mems: 15 + post_call_invokes: 60 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 396 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 603 + call_imms: 46 + call_regs: 6 + call_mems: 15 + post_call_invokes: 64 + excluded_call_imms: 3 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 400 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 615 + call_imms: 46 + call_regs: 7 + call_mems: 17 + post_call_invokes: 64 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 17 + jmp_regs: 3 + + jmp_cond_imms: 407 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 626 + call_imms: 48 + call_regs: 8 + call_mems: 18 + post_call_invokes: 66 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 46 + jmp_mems: 18 + jmp_regs: 3 + + jmp_cond_imms: 411 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 637 + call_imms: 50 + call_regs: 9 + call_mems: 19 + post_call_invokes: 68 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 47 + jmp_mems: 19 + jmp_regs: 3 + + jmp_cond_imms: 414 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 648 + call_imms: 52 + call_regs: 9 + call_mems: 20 + post_call_invokes: 70 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 47 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 419 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 660 + call_imms: 52 + call_regs: 10 + call_mems: 20 + post_call_invokes: 72 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 49 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 426 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 672 + call_imms: 52 + call_regs: 10 + call_mems: 20 + post_call_invokes: 72 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 51 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 436 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 683 + call_imms: 53 + call_regs: 11 + call_mems: 21 + post_call_invokes: 73 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 52 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 442 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 697 + call_imms: 53 + call_regs: 11 + call_mems: 22 + post_call_invokes: 74 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 53 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 453 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 709 + call_imms: 53 + call_regs: 13 + call_mems: 22 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 53 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 460 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 720 + call_imms: 53 + call_regs: 13 + call_mems: 22 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 55 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 469 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 730 + call_imms: 54 + call_regs: 13 + call_mems: 24 + post_call_invokes: 77 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 56 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 475 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 740 + call_imms: 54 + call_regs: 13 + call_mems: 24 + post_call_invokes: 80 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 57 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 481 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 753 + call_imms: 54 + call_regs: 14 + call_mems: 24 + post_call_invokes: 81 + excluded_call_imms: 5 + ret_slow_paths: 3 + + jmp_imms: 58 + jmp_mems: 20 + jmp_regs: 3 + + jmp_cond_imms: 491 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 + + +total_transitions: 3 + call_imms: 0 + call_regs: 0 + call_mems: 0 + post_call_invokes: 0 + excluded_call_imms: 0 + ret_slow_paths: 0 + + jmp_imms: 1 + jmp_mems: 1 + jmp_regs: 0 + + jmp_cond_imms: 1 + jmp_cond_mems: 0 + jmp_cond_regs: 0 + jmp_cond_jcxzs: 0 + + jmp_continuations: 0 +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input +Running: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) +Done: /home/jon/git/AFLplusplus/frida_mode/test/output/build/frida-out/default/.cur_input: (3 bytes) diff --git a/frida_mode/test/output/frida_stdout.txt b/frida_mode/test/output/frida_stdout.txt new file mode 100644 index 00000000..8832681d --- /dev/null +++ b/frida_mode/test/output/frida_stdout.txt @@ -0,0 +1,349 @@ +OG Range - 0x00007FFFF7FFE000 - 0x00007FFFF7FFF000 +[+] CMPLOG Range - 0x00007FFFF7FFD000 - 0x00007FFFF7FFE000 +[+] CMPLOG Range - 0x00007FFFF7FFC000 - 0x00007FFFF7FFD000 +[+] CMPLOG Range - 0x00007FFFF7FF3000 - 0x00007FFFF7FFB000 +[+] CMPLOG Range - 0x00007FFFF7FD0000 - 0x00007FFFF7FF3000 +[+] CMPLOG Range - 0x00007FFFF7FCF000 - 0x00007FFFF7FD0000 +[+] CMPLOG Range - 0x00007FFFF7FCE000 - 0x00007FFFF7FCF000 +[+] CMPLOG Range - 0x00007FFFF7FCB000 - 0x00007FFFF7FCE000 +[+] CMPLOG Range - 0x00007FFFF7DC4000 - 0x00007FFFF7FCB000 +[+] CMPLOG Range - 0x00007FFFF7DBC000 - 0x00007FFFF7DC4000 +[+] CMPLOG Range - 0x00007FFFF7DB0000 - 0x00007FFFF7DBC000 +[+] CMPLOG Range - 0x00007FFFF7A94000 - 0x00007FFFF7DB0000 +[+] CMPLOG Range - 0x00007FFFF7942000 - 0x00007FFFF7A94000 +[+] CMPLOG Range - 0x00007FFFF78BF000 - 0x00007FFFF7942000 +[+] CMPLOG Range - 0x00007FFFF78AF000 - 0x00007FFFF78BF000 +[+] CMPLOG Range - 0x00007FFFF78AA000 - 0x00007FFFF78AB000 +[+] CMPLOG Range - 0x00007FFFF78A9000 - 0x00007FFFF78AA000 +[+] CMPLOG Range - 0x00007FFFF78A2000 - 0x00007FFFF78A6000 +[+] CMPLOG Range - 0x00007FFFF789F000 - 0x00007FFFF78A2000 +[+] CMPLOG Range - 0x00007FFFF789C000 - 0x00007FFFF789F000 +[+] CMPLOG Range - 0x00007FFFF7851000 - 0x00007FFFF789B000 +[+] CMPLOG Range - 0x00007FFFF76DB000 - 0x00007FFFF7851000 +[+] CMPLOG Range - 0x00007FFFF76DA000 - 0x00007FFFF76DB000 +[+] CMPLOG Range - 0x00007FFFF76D9000 - 0x00007FFFF76DA000 +[+] CMPLOG Range - 0x00007FFFF76B4000 - 0x00007FFFF76D9000 +[+] CMPLOG Range - 0x00007FFFF76B0000 - 0x00007FFFF76B4000 +[+] CMPLOG Range - 0x00007FFFF76AF000 - 0x00007FFFF76B0000 +[+] CMPLOG Range - 0x00007FFFF76AE000 - 0x00007FFFF76AF000 +[+] CMPLOG Range - 0x00007FFFF76A9000 - 0x00007FFFF76AE000 +[+] CMPLOG Range - 0x00007FFFF7698000 - 0x00007FFFF76A9000 +[+] CMPLOG Range - 0x00007FFFF7691000 - 0x00007FFFF7698000 +[+] CMPLOG Range - 0x00007FFFF768F000 - 0x00007FFFF7691000 +[+] CMPLOG Range - 0x00007FFFF768E000 - 0x00007FFFF768F000 +[+] CMPLOG Range - 0x00007FFFF768D000 - 0x00007FFFF768E000 +[+] CMPLOG Range - 0x00007FFFF7689000 - 0x00007FFFF768C000 +[+] CMPLOG Range - 0x00007FFFF7679000 - 0x00007FFFF7689000 +[+] CMPLOG Range - 0x00007FFFF7675000 - 0x00007FFFF7679000 +[+] CMPLOG Range - 0x00007FFFF7674000 - 0x00007FFFF7675000 +[+] CMPLOG Range - 0x00007FFFF7673000 - 0x00007FFFF7674000 +[+] CMPLOG Range - 0x00007FFFF7672000 - 0x00007FFFF7673000 +[+] CMPLOG Range - 0x00007FFFF7670000 - 0x00007FFFF7672000 +[+] CMPLOG Range - 0x00007FFFF766F000 - 0x00007FFFF7670000 +[+] CMPLOG Range - 0x00007FFFF766D000 - 0x00007FFFF766F000 +[+] Redirect 1 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stdout.txt' +[+] Redirect 2 -> '/home/jon/git/AFLplusplus/frida_mode/test/output/frida_stderr.txt' +[+] Instrumentation - persistent mode [ ] (0x0000000000000000) +[+] Instrumentation - persistent count [ ] (0) +[+] Instrumentation - hook [(null)] +[+] Instrumentation - persistent ret [ ] (0x0000000000000000) +[+] Instrumentation - persistent ret offset [ ] (0) +[+] Instrumentation - prefetch [X] +[+] Range: Modules Length: 54 +[+] Range: Modules Idx: 0 - 0x0000555555554000-0x0000555555555000 +[+] Range: Modules Idx: 1 - 0x0000555555555000-0x0000555555556000 +[+] Range: Modules Idx: 2 - 0x0000555555556000-0x0000555555557000 +[+] Range: Modules Idx: 3 - 0x0000555555557000-0x0000555555558000 +[+] Range: Modules Idx: 4 - 0x0000555555558000-0x0000555555559000 +[+] Range: Modules Idx: 5 - 0x0000555555559000-0x000055555557a000 +[+] Range: Modules Idx: 6 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: Modules Idx: 7 - 0x00007ffff766d000-0x00007ffff766f000 +[+] Range: Modules Idx: 8 - 0x00007ffff766f000-0x00007ffff7670000 +[+] Range: Modules Idx: 9 - 0x00007ffff7670000-0x00007ffff7672000 +[+] Range: Modules Idx: 10 - 0x00007ffff7672000-0x00007ffff7673000 +[+] Range: Modules Idx: 11 - 0x00007ffff7673000-0x00007ffff7674000 +[+] Range: Modules Idx: 12 - 0x00007ffff7674000-0x00007ffff7675000 +[+] Range: Modules Idx: 13 - 0x00007ffff7675000-0x00007ffff7679000 +[+] Range: Modules Idx: 14 - 0x00007ffff7679000-0x00007ffff7689000 +[+] Range: Modules Idx: 15 - 0x00007ffff7689000-0x00007ffff768c000 +[+] Range: Modules Idx: 16 - 0x00007ffff768c000-0x00007ffff768d000 +[+] Range: Modules Idx: 17 - 0x00007ffff768d000-0x00007ffff768e000 +[+] Range: Modules Idx: 18 - 0x00007ffff768e000-0x00007ffff768f000 +[+] Range: Modules Idx: 19 - 0x00007ffff768f000-0x00007ffff7691000 +[+] Range: Modules Idx: 20 - 0x00007ffff7691000-0x00007ffff7698000 +[+] Range: Modules Idx: 21 - 0x00007ffff7698000-0x00007ffff76a9000 +[+] Range: Modules Idx: 22 - 0x00007ffff76a9000-0x00007ffff76ae000 +[+] Range: Modules Idx: 23 - 0x00007ffff76ae000-0x00007ffff76af000 +[+] Range: Modules Idx: 24 - 0x00007ffff76af000-0x00007ffff76b0000 +[+] Range: Modules Idx: 25 - 0x00007ffff76b0000-0x00007ffff76b4000 +[+] Range: Modules Idx: 26 - 0x00007ffff76b4000-0x00007ffff76d9000 +[+] Range: Modules Idx: 27 - 0x00007ffff76d9000-0x00007ffff76da000 +[+] Range: Modules Idx: 28 - 0x00007ffff76da000-0x00007ffff76db000 +[+] Range: Modules Idx: 29 - 0x00007ffff76db000-0x00007ffff7851000 +[+] Range: Modules Idx: 30 - 0x00007ffff7851000-0x00007ffff789b000 +[+] Range: Modules Idx: 31 - 0x00007ffff789b000-0x00007ffff789c000 +[+] Range: Modules Idx: 32 - 0x00007ffff789c000-0x00007ffff789f000 +[+] Range: Modules Idx: 33 - 0x00007ffff789f000-0x00007ffff78a2000 +[+] Range: Modules Idx: 34 - 0x00007ffff78a2000-0x00007ffff78a6000 +[+] Range: Modules Idx: 35 - 0x00007ffff78a9000-0x00007ffff78aa000 +[+] Range: Modules Idx: 36 - 0x00007ffff78aa000-0x00007ffff78ab000 +[+] Range: Modules Idx: 37 - 0x00007ffff78af000-0x00007ffff78bf000 +[+] Range: Modules Idx: 38 - 0x00007ffff78bf000-0x00007ffff7942000 +[+] Range: Modules Idx: 39 - 0x00007ffff7942000-0x00007ffff7a94000 +[+] Range: Modules Idx: 40 - 0x00007ffff7a94000-0x00007ffff7db0000 +[+] Range: Modules Idx: 41 - 0x00007ffff7db0000-0x00007ffff7dbc000 +[+] Range: Modules Idx: 42 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: Modules Idx: 43 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: Modules Idx: 44 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: Modules Idx: 45 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: Modules Idx: 46 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: Modules Idx: 47 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: Modules Idx: 48 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: Modules Idx: 49 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: Modules Idx: 50 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: Modules Idx: 51 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: Modules Idx: 52 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: Modules Idx: 53 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: AFL_INST_LIBS Length: 1 +[+] Range: AFL_INST_LIBS Idx: 0 - 0x0000555555555160-0x0000555555555335 +[+] Range: step1 Length: 1 +[+] Range: step1 Idx: 0 - 0x0000555555555160-0x0000555555555335 +[+] Range: step2 Length: 1 +[+] Range: step2 Idx: 0 - 0x0000555555555160-0x0000555555555335 +[+] Range: step3 Length: 1 +[+] Range: step3 Idx: 0 - 0x0000555555555160-0x0000555555555335 +[+] Range: step4 Length: 55 +[+] Range: step4 Idx: 0 - 0x0000555555554000-0x0000555555555000 +[+] Range: step4 Idx: 1 - 0x0000555555555000-0x0000555555555160 +[+] Range: step4 Idx: 2 - 0x0000555555555335-0x0000555555556000 +[+] Range: step4 Idx: 3 - 0x0000555555556000-0x0000555555557000 +[+] Range: step4 Idx: 4 - 0x0000555555557000-0x0000555555558000 +[+] Range: step4 Idx: 5 - 0x0000555555558000-0x0000555555559000 +[+] Range: step4 Idx: 6 - 0x0000555555559000-0x000055555557a000 +[+] Range: step4 Idx: 7 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: step4 Idx: 8 - 0x00007ffff766d000-0x00007ffff766f000 +[+] Range: step4 Idx: 9 - 0x00007ffff766f000-0x00007ffff7670000 +[+] Range: step4 Idx: 10 - 0x00007ffff7670000-0x00007ffff7672000 +[+] Range: step4 Idx: 11 - 0x00007ffff7672000-0x00007ffff7673000 +[+] Range: step4 Idx: 12 - 0x00007ffff7673000-0x00007ffff7674000 +[+] Range: step4 Idx: 13 - 0x00007ffff7674000-0x00007ffff7675000 +[+] Range: step4 Idx: 14 - 0x00007ffff7675000-0x00007ffff7679000 +[+] Range: step4 Idx: 15 - 0x00007ffff7679000-0x00007ffff7689000 +[+] Range: step4 Idx: 16 - 0x00007ffff7689000-0x00007ffff768c000 +[+] Range: step4 Idx: 17 - 0x00007ffff768c000-0x00007ffff768d000 +[+] Range: step4 Idx: 18 - 0x00007ffff768d000-0x00007ffff768e000 +[+] Range: step4 Idx: 19 - 0x00007ffff768e000-0x00007ffff768f000 +[+] Range: step4 Idx: 20 - 0x00007ffff768f000-0x00007ffff7691000 +[+] Range: step4 Idx: 21 - 0x00007ffff7691000-0x00007ffff7698000 +[+] Range: step4 Idx: 22 - 0x00007ffff7698000-0x00007ffff76a9000 +[+] Range: step4 Idx: 23 - 0x00007ffff76a9000-0x00007ffff76ae000 +[+] Range: step4 Idx: 24 - 0x00007ffff76ae000-0x00007ffff76af000 +[+] Range: step4 Idx: 25 - 0x00007ffff76af000-0x00007ffff76b0000 +[+] Range: step4 Idx: 26 - 0x00007ffff76b0000-0x00007ffff76b4000 +[+] Range: step4 Idx: 27 - 0x00007ffff76b4000-0x00007ffff76d9000 +[+] Range: step4 Idx: 28 - 0x00007ffff76d9000-0x00007ffff76da000 +[+] Range: step4 Idx: 29 - 0x00007ffff76da000-0x00007ffff76db000 +[+] Range: step4 Idx: 30 - 0x00007ffff76db000-0x00007ffff7851000 +[+] Range: step4 Idx: 31 - 0x00007ffff7851000-0x00007ffff789b000 +[+] Range: step4 Idx: 32 - 0x00007ffff789b000-0x00007ffff789c000 +[+] Range: step4 Idx: 33 - 0x00007ffff789c000-0x00007ffff789f000 +[+] Range: step4 Idx: 34 - 0x00007ffff789f000-0x00007ffff78a2000 +[+] Range: step4 Idx: 35 - 0x00007ffff78a2000-0x00007ffff78a6000 +[+] Range: step4 Idx: 36 - 0x00007ffff78a9000-0x00007ffff78aa000 +[+] Range: step4 Idx: 37 - 0x00007ffff78aa000-0x00007ffff78ab000 +[+] Range: step4 Idx: 38 - 0x00007ffff78af000-0x00007ffff78bf000 +[+] Range: step4 Idx: 39 - 0x00007ffff78bf000-0x00007ffff7942000 +[+] Range: step4 Idx: 40 - 0x00007ffff7942000-0x00007ffff7a94000 +[+] Range: step4 Idx: 41 - 0x00007ffff7a94000-0x00007ffff7db0000 +[+] Range: step4 Idx: 42 - 0x00007ffff7db0000-0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! +0x00007ffff7dbc000 +[+] Range: step4 Idx: 43 - 0x00007ffff7dbc000-0x00007ffff7dc4000 +[+] Range: step4 Idx: 44 - 0x00007ffff7dc4000-0x00007ffff7fcb000 +[+] Range: step4 Idx: 45 - 0x00007ffff7fcb000-0x00007ffff7fce000 +[+] Range: step4 Idx: 46 - 0x00007ffff7fce000-0x00007ffff7fcf000 +[+] Range: step4 Idx: 47 - 0x00007ffff7fcf000-0x00007ffff7fd0000 +[+] Range: step4 Idx: 48 - 0x00007ffff7fd0000-0x00007ffff7ff3000 +[+] Range: step4 Idx: 49 - 0x00007ffff7ff3000-0x00007ffff7ffb000 +[+] Range: step4 Idx: 50 - 0x00007ffff7ffc000-0x00007ffff7ffd000 +[+] Range: step4 Idx: 51 - 0x00007ffff7ffd000-0x00007ffff7ffe000 +[+] Range: step4 Idx: 52 - 0x00007ffff7ffe000-0x00007ffff7fff000 +[+] Range: step4 Idx: 53 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: step4 Idx: 54 - 0xffffffffff600000-0xffffffffff601000 +[+] Range: final Length: 9 +[+] Range: final Idx: 0 - 0x0000555555554000-0x0000555555555160 +[+] Range: final Idx: 1 - 0x0000555555555335-0x000055555557a000 +[+] Range: final Idx: 2 - 0x00007ffff7615000-0x00007ffff7625000 +[+] Range: final Idx: 3 - 0x00007ffff766d000-0x00007ffff78a6000 +[+] Range: final Idx: 4 - 0x00007ffff78a9000-0x00007ffff78ab000 +[+] Range: final Idx: 5 - 0x00007ffff78af000-0x00007ffff7ffb000 +[+] Range: final Idx: 6 - 0x00007ffff7ffc000-0x00007ffff7fff000 +[+] Range: final Idx: 7 - 0x00007ffffffdd000-0x00007ffffffff000 +[+] Range: final Idx: 8 - 0xffffffffff600000-0xffffffffff601000 +Looks like a zero to me! diff --git a/frida_mode/test/output/testinstr.c b/frida_mode/test/output/testinstr.c new file mode 100644 index 00000000..5e26fc46 --- /dev/null +++ b/frida_mode/test/output/testinstr.c @@ -0,0 +1,112 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile new file mode 100644 index 00000000..df48d065 --- /dev/null +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -0,0 +1,105 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x56555000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000) +endif + +AFL_FRIDA_PERSISTENT_RETADDR_OFFSET:=0x50 + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ + AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +debug: $(TESTINSTR_DATA_FILE) + gdb \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET)' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ + --ex 'set environment AFL_DEBUG_CHILD=1' \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + +run: $(TESTINSTR_DATA_FILE) + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ + AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ + AFL_DEBUG_CHILD=1 \ + LD_PRELOAD=$(ROOT)afl-frida-trace.so \ + $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) diff --git a/frida_mode/test/persistent_ret/Makefile b/frida_mode/test/persistent_ret/Makefile new file mode 100644 index 00000000..e3deddbd --- /dev/null +++ b/frida_mode/test/persistent_ret/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +frida_ret: + @gmake frida_ret + +debug: + @gmake debug + +run: + @gmake run diff --git a/frida_mode/test/persistent_ret/get_symbol_addr.py b/frida_mode/test/persistent_ret/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/persistent_ret/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/persistent_ret/testinstr.c b/frida_mode/test/persistent_ret/testinstr.c new file mode 100644 index 00000000..6cb88a50 --- /dev/null +++ b/frida_mode/test/persistent_ret/testinstr.c @@ -0,0 +1,120 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void testinstr(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +void slow() { + + usleep(100000); + +} + +TESTINSTR_SECTION int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + slow(); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile new file mode 100644 index 00000000..9f0b31d3 --- /dev/null +++ b/frida_mode/test/re2/GNUmakefile @@ -0,0 +1,170 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBRE2_BUILD_DIR:=$(BUILD_DIR)libre2/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +RE2TEST_BUILD_DIR:=$(BUILD_DIR)re2test/ + +LIBRE2_URL:=https://github.com/google/re2.git +LIBRE2_DIR:=$(LIBRE2_BUILD_DIR)libre2/ +LIBRE2_MAKEFILE:=$(LIBRE2_DIR)Makefile +LIBRE2_LIB:=$(LIBRE2_DIR)obj/libre2.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c" + +RE2TEST_FILE:=$(RE2TEST_BUILD_DIR)target.cc +RE2TEST_OBJ:=$(RE2TEST_BUILD_DIR)target.o +RE2TEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/re2-2014-12-09/target.cc" + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +AFLPP_DRIVER_DUMMY_INPUT:=$(TEST_DATA_DIR)in + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean qemu frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### RE2TEST ######## + +$(RE2TEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(RE2TEST_FILE): | $(RE2TEST_BUILD_DIR) + wget -O $@ $(RE2TEST_URL) + +$(RE2TEST_OBJ): $(RE2TEST_FILE) | $(LIBRE2_MAKEFILE) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBRE2_DIR) -o $@ -c $< + +######### LIBRE2 ######## + +$(LIBRE2_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBRE2_MAKEFILE): $(LIBRE2_BUILD_DIR) + git clone https://github.com/google/re2.git $(LIBRE2_DIR) + cd $(LIBRE2_DIR) && git checkout 499ef7eff7455ce9c9fae86111d4a77b6ac335de + +$(LIBRE2_LIB): $(LIBRE2_MAKEFILE) + make -C $(LIBRE2_DIR) -j $(shell nproc) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR) + truncate -s 1M $@ + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +qemu: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_QEMU_PERSISTENT_GPR=1 \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -Q \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(TEST_DATA_DIR)basn0g01.re2 diff --git a/frida_mode/test/re2/Makefile b/frida_mode/test/re2/Makefile new file mode 100644 index 00000000..00b2b287 --- /dev/null +++ b/frida_mode/test/re2/Makefile @@ -0,0 +1,22 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +debug: + @gmake debug + +hook: + @gmake hook diff --git a/frida_mode/test/re2/aflpp_qemu_driver_hook.c b/frida_mode/test/re2/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/re2/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include +#include + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/re2/get_symbol_addr.py b/frida_mode/test/re2/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/re2/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 72f956b9..4aba3bdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -385,10 +385,10 @@ typedef struct afl_env_vars { afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, - afl_exit_on_seed_issues; + afl_exit_on_seed_issues, afl_try_affinity; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, - *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, + *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries, *afl_kill_signal, *afl_target_env, diff --git a/include/config.h b/include/config.h index aa24ea6c..80cdb684 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,7 @@ cases that show variable behavior): */ #define CAL_CYCLES 8U -#define CAL_CYCLES_LONG 40U +#define CAL_CYCLES_LONG 20U /* Number of subsequent timeouts before abandoning an input file: */ @@ -163,7 +163,7 @@ /* Maximum number of unique hangs or crashes to record: */ #define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 5000U +#define KEEP_UNIQUE_CRASH 10000U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/include/envs.h b/include/envs.h index f1314bad..08b3284a 100644 --- a/include/envs.h +++ b/include/envs.h @@ -55,14 +55,22 @@ static char *afl_environment_variables[] = { "AFL_FORCE_UI", "AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_EXCLUDE_RANGES", + "AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_RANGES", - "AFL_FRIDA_INST_STRICT", "AFL_FRIDA_INST_TRACE", + "AFL_FRIDA_OUTPUT_STDOUT", + "AFL_FRIDA_OUTPUT_STDERR", "AFL_FRIDA_PERSISTENT_ADDR", "AFL_FRIDA_PERSISTENT_CNT", + "AFL_FRIDA_PERSISTENT_DEBUG", "AFL_FRIDA_PERSISTENT_HOOK", + "AFL_FRIDA_PERSISTENT_RET", + "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET", + "AFL_FRIDA_STATS_FILE", + "AFL_FRIDA_STATS_INTERVAL", + "AFL_FRIDA_STATS_TRANSITIONS", "AFL_FUZZER_ARGS", // oss-fuzz "AFL_GDB", "AFL_GCC_ALLOWLIST", @@ -120,6 +128,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_INSTRUMENT_FILE", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", + "AFL_TRY_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 38cb5ba6..d28479d9 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -110,22 +110,23 @@ takes priority over any included ranges or AFL_INST_LIBS. CompareCoverage is a sub-instrumentation with effects similar to laf-intel. -The environment variable that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL. -There is also ./libcompcov/ which implements CompareCoverage for *cmp functions -(splitting memcmp, strncmp, etc. to make these conditions easier solvable by -afl-fuzz). +You have to set `AFL_PRELOAD=/path/to/libcompcov.so` together with +setting the AFL_COMPCOV_LEVEL you want to enable it. AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate -values / read-only memory. AFL_COMPCOV_LEVEL=2 instruments all -comparison instructions and memory comparison functions when libcompcov -is preloaded. -AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables also -the instrumentation of the floating-point comparisons on x86 and x86_64 (experimental). +values / read-only memory. + +AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and memory +comparison functions when libcompcov is preloaded. + +AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables +also the instrumentation of the floating-point comparisons on x86 and x86_64 +(experimental). Integer comparison instructions are currently instrumented only on the x86, x86_64, arm and aarch64 targets. -Highly recommended. +Recommended, but not as good as CMPLOG mode (see below). ## 8) CMPLOG mode diff --git a/src/afl-cc.c b/src/afl-cc.c index ebe11525..8af8e7b0 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1224,6 +1224,14 @@ int main(int argc, char **argv, char **envp) { if (strncmp(argv[i], "--afl", 5) == 0) { + if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) { + + passthrough = 1; + argv[i] = "-g"; // we have to overwrite it, -g is always good + continue; + + } + if (compiler_mode) WARNF( "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " @@ -1821,6 +1829,12 @@ int main(int argc, char **argv, char **envp) { "If anything fails - be sure to read README.lto.md!\n"); #endif + SAYF( + "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. " + "(this is helpful\n" + "in some build systems if you do not want to instrument " + "everything.\n"); + } SAYF( diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index b277802b..88b5bc02 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 lockfile[PATH_MAX] = ""; s32 i; - if (afl->afl_env.afl_no_affinity) { + if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { if (afl->cpu_to_bind != -1) { @@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!bind_cpu(afl, afl->cpu_to_bind)) { - FATAL( - "Could not bind to requested CPU %d! Make sure you passed a valid " - "-b.", - afl->cpu_to_bind); + if (afl->afl_env.afl_try_affinity) { + + WARNF( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } else { + + FATAL( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } } @@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) { "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " "Starting\n" - " another fuzzer on this machine is probably a bad plan, but if " - "you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", - afl->cpu_core_count); - FATAL("No more free CPU cores"); + " another fuzzer on this machine is probably a bad plan.\n" + "%s", + afl->cpu_core_count, + afl->afl_env.afl_try_affinity ? "" + : " If you are sure, you can set " + "AFL_NO_AFFINITY and try again.\n"); + + if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } } @@ -823,7 +837,6 @@ void perform_dry_run(afl_state_t *afl) { struct queue_entry *q; u32 cal_failures = 0, idx; - u8 * skip_crashes = afl->afl_env.afl_skip_crashes; u8 * use_mem; for (idx = 0; idx < afl->queued_paths; idx++) { @@ -923,27 +936,6 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } - if (skip_crashes) { - - if (afl->fsrv.uses_crash_exitcode) { - - WARNF( - "Test case results in a crash or AFL_CRASH_EXITCODE %d " - "(skipping)", - (int)(s8)afl->fsrv.crash_exitcode); - - } else { - - WARNF("Test case results in a crash (skipping)"); - - } - - q->cal_failed = CAL_CHANCES; - ++cal_failures; - break; - - } - if (afl->fsrv.mem_limit) { u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -1117,14 +1109,12 @@ void perform_dry_run(afl_state_t *afl) { if (cal_failures == afl->queued_paths) { - FATAL("All test cases time out%s, giving up!", - skip_crashes ? " or crash" : ""); + FATAL("All test cases time out or crash, giving up!"); } - WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, - ((double)cal_failures) * 100 / afl->queued_paths, - skip_crashes ? " or crashes" : ""); + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.", + cal_failures, ((double)cal_failures) * 100 / afl->queued_paths); if (cal_failures * 5 > afl->queued_paths) { diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 8760194c..3aa97635 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) - FATAL("deinit function not found in python module"); + WARNF("deinit function not found in python module"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6e5210b8..5a481639 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -410,7 +410,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = CAL_CYCLES_LONG; + afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index c886cb28..0658070e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -202,12 +202,18 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_affinity = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TRY_AFFINITY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_try_affinity = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_SKIP_CRASHES", afl_environment_variable_len)) { - afl->afl_env.afl_skip_crashes = - (u8 *)get_afl_env(afl_environment_variables[i]); + // we should mark this obsolete in a few versions } else if (!strncmp(env, "AFL_HANG_TMOUT", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 35fb2d04..a3a623d9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -35,6 +35,10 @@ #include #endif +#ifdef __APPLE__ + #include +#endif + #ifdef PROFILING extern u64 time_spent_working; #endif @@ -220,6 +224,7 @@ static void usage(u8 *argv0, int more_help) { " then they are randomly selected instead all of them being\n" " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" @@ -240,7 +245,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" - "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" + //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" "AFL_STATSD: enables StatsD metrics collection\n" "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n" "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" @@ -2296,26 +2301,9 @@ stop_fuzzing: afl_fsrv_deinit(&afl->fsrv); /* remove tmpfile */ - if (afl->tmp_dir != NULL && !afl->in_place_resume) { - - char tmpfile[PATH_MAX]; - - if (afl->file_extension) { - - snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, - afl->file_extension); + if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { - } else { - - snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir); - - } - - if (unlink(tmpfile) != 0) { - - FATAL("Could not unlink current input file: %s.", tmpfile); - - } + (void)unlink(afl->fsrv.out_file); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index d7af668c..96b72dd9 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -235,6 +235,9 @@ 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); return ret; } diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md index 01bd10c0..f03c2fe3 100644 --- a/utils/aflpp_driver/README.md +++ b/utils/aflpp_driver/README.md @@ -13,6 +13,12 @@ If this is the clang compile command to build for libfuzzer: then just switch `clang++` with `afl-clang-fast++` and our compiler will magically insert libAFLDriver.a :) +To use shared-memory testcases, you need nothing to do. +To use stdin testcases give `-` as the only command line parameter. +To use file input testcases give `@@` as the only command line parameter. + +IMPORTANT: if you use `afl-cmin` or `afl-cmin.bash` then either pass `-` +or `@@` as command line parameters. ## aflpp_qemu_driver diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index ad781e64..c094c425 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -174,11 +174,17 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { static int ExecuteFilesOnyByOne(int argc, char **argv) { unsigned char *buf = (unsigned char *)malloc(MAX_FILE); + for (int i = 1; i < argc; i++) { - int fd = open(argv[i], O_RDONLY); - if (fd == -1) continue; + int fd = 0; + + if (strcmp(argv[i], "-") != 0) { fd = open(argv[i], O_RDONLY); } + + if (fd == -1) { continue; } + ssize_t length = read(fd, buf, MAX_FILE); + if (length > 0) { printf("Reading %zu bytes from %s\n", length, argv[i]); @@ -187,7 +193,7 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) { } - close(fd); + if (fd > 0) { close(fd); } } @@ -199,15 +205,19 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) { int main(int argc, char **argv) { printf( - "======================= INFO =========================\n" + "============================== INFO ================================\n" "This binary is built for afl++.\n" + "To use with afl-cmin or afl-cmin.bash pass '-' as single command line " + "option\n" "To run the target function on individual input(s) execute this:\n" " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" "To fuzz with afl-fuzz execute this:\n" " afl-fuzz [afl-flags] -- %s [-N]\n" "afl-fuzz will run N iterations before re-spawning the process (default: " "INT_MAX)\n" - "======================================================\n", + "For stdin input processing, pass '-' as single command line option.\n" + "For file input processing, pass '@@' as single command line option.\n" + "===================================================================\n", argv[0], argv[0]); if (getenv("AFL_GDB")) { @@ -237,22 +247,35 @@ int main(int argc, char **argv) { memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, sizeof(AFL_DEFER_FORKSVR)); + int N = INT_MAX; - if (argc == 2 && argv[1][0] == '-') + + if (argc == 2 && !strcmp(argv[1], "-")) { + + __afl_sharedmem_fuzzing = 0; + __afl_manual_init(); + return ExecuteFilesOnyByOne(argc, argv); + + } else if (argc == 2 && argv[1][0] == '-') { + N = atoi(argv[1] + 1); - else if (argc == 2 && (N = atoi(argv[1])) > 0) + + } else if (argc == 2 && (N = atoi(argv[1])) > 0) { + printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); - else if (argc > 1) { + + } else if (argc > 1) { __afl_sharedmem_fuzzing = 0; - __afl_manual_init(); + + if (argc == 2) { __afl_manual_init(); } + return ExecuteFilesOnyByOne(argc, argv); } assert(N > 0); - // if (!getenv("AFL_DRIVER_DONT_DEFER")) __afl_manual_init(); // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization @@ -271,6 +294,7 @@ int main(int argc, char **argv) { fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); fprintf(stderr, "\n"); #endif + if (*__afl_fuzz_len) { num_runs++; -- cgit 1.4.1 From eb74a7a8004e8281cda62525bbc1f3bbe7f5d9da Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 30 May 2021 12:43:30 +0200 Subject: add documentation for AFL_LLVM_THREADSAFE_INST --- docs/Changelog.md | 1 + docs/env_variables.md | 5 +++++ instrumentation/README.llvm.md | 4 ++++ instrumentation/README.neverzero.md | 5 +++++ src/afl-cc.c | 1 + 5 files changed, 16 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9c9a3976..d8e96bf3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,7 @@ sending a mail to . - Removed automatic linking with -lc++ for LTO mode - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - add -d (add dead fuzzer stats) to afl-whatsup + - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index 0100ffac..d9a774aa 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,6 +231,11 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. +### Thread safe instrumentation counters (in mode LLVM CLASSIC) + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe counters. + The overhead is a bit higher compared to the older non-thread safe case. + `AFL_LLVM_NOT_ZERO` and `AFL_LLVM_SKIP_NEVERZERO` are supported (see below). + ### NOT_ZERO - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index adce6c1d..a9d51829 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,6 +144,10 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) +Support for thread safe counters has been added for mode LLVM CLASSIC. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in +multi threaded apps for a slightly higher instrumentation overhead. + ## 4) Snapshot feature To speed up fuzzing you can use a linux loadable kernel module which enables diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md index 49104e00..06334eab 100644 --- a/instrumentation/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -33,3 +33,8 @@ AFL_LLVM_SKIP_NEVERZERO=1 ``` If the target does not have extensive loops or functions that are called a lot then this can give a small performance boost. + +Please note that the default counter implementations are not thread safe! + +Support for thread safe counters in mode LLVM CLASSIC can be activated with setting +`AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file diff --git a/src/afl-cc.c b/src/afl-cc.c index 1f89bac5..132f5f83 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1757,6 +1757,7 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters\n" COUNTER_BEHAVIOUR -- cgit 1.4.1 From 76653544056ce2334b6523252e91a8f8a6ac9dcb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 10:13:16 +0200 Subject: threadsafe doc fixes, code format --- README.md | 3 +- docs/Changelog.md | 3 +- docs/env_variables.md | 9 +- frida_mode/src/instrument/instrument_debug.c | 2 +- frida_mode/src/stats/stats.c | 4 +- instrumentation/README.llvm.md | 7 +- instrumentation/SanitizerCoverageLTO.so.cc | 7 +- instrumentation/SanitizerCoveragePCGUARD.so.cc | 6 +- instrumentation/afl-llvm-lto-instrumentation.so.cc | 11 +- instrumentation/afl-llvm-pass.so.cc | 116 +++++++++++++-------- qemu_mode/libqasan/libqasan.c | 5 +- src/afl-cc.c | 3 +- src/afl-fuzz-one.c | 1 + src/afl-fuzz.c | 7 +- 14 files changed, 106 insertions(+), 78 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 69e2d14a..c04dba98 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ behaviours and defaults: | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| + | Threadsafe counters | | x(3) | | | | | | NeverZero | x86[_64]| x(1) | x | x | x | x | | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | @@ -104,7 +105,7 @@ behaviours and defaults: 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin - 3. (currently unassigned) + 3. with `AFL_LLVM_THREADSAFE_INST`, disables NeverZero 4. with pcguard mode and LTO mode for LLVM 11 and newer 5. upcoming, development in the branch 6. not compatible with LTO instrumentation and needs at least LLVM v4.1 diff --git a/docs/Changelog.md b/docs/Changelog.md index d8ffe498..29ea918b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -41,6 +41,8 @@ sending a mail to . it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore + - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`), + note that this disables never zero counters. - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD @@ -58,7 +60,6 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename - afl-showmap/cmin will now process queue items in alphabetical order diff --git a/docs/env_variables.md b/docs/env_variables.md index b4b866ab..38a67bc7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,10 +231,11 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. -### Thread safe instrumentation counters (in mode LLVM CLASSIC) - - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe counters. - The overhead is a bit higher compared to the older non-thread safe case. - `AFL_LLVM_NOT_ZERO` and `AFL_LLVM_SKIP_NEVERZERO` are supported (see below). +### Thread safe instrumentation counters (in all modes) + + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread + safe counters. The overhead is a little bit higher compared to the older + non-thread safe case. Note that this disables neverzero (see below). ### NOT_ZERO diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index be72ef89..f8c1df77 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -17,7 +17,7 @@ static void instrument_debug(char *format, ...) { va_list ap; char buffer[4096] = {0}; int ret; - int len; + int len; va_start(ap, format); ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 890a8d6b..662fb6d5 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -96,10 +96,10 @@ void stats_init(void) { void stats_vprint(int fd, char *format, va_list ap) { char buffer[4096] = {0}; - int ret; + int ret; int len; - if(vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } len = strnlen(buffer, sizeof(buffer)); IGNORED_RETURN(write(fd, buffer, len)); diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 02722588..8ce5afb9 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,9 +144,10 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) -Support for thread safe counters has been added for mode LLVM CLASSIC. -Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in -multi threaded apps for a slightly higher instrumentation overhead. +Support for thread safe counters has been added for all modes. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision +in multi threaded apps for a slightly higher instrumentation overhead. +This also disables the nozero counter default for performance reasons. ## 4) Snapshot feature diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 58969e18..20f1856e 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1497,14 +1497,12 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ - if (use_threadsafe_counters) { /* Atomic */ + if (use_threadsafe_counters) { /* Atomic */ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); - } - else - { + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(Mo->getMDKindID("nosanitize"), @@ -1524,6 +1522,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); } + // done :) inst++; diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index dbddad0a..4a8c9e28 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1069,16 +1069,14 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, /* Load counter for CurLoc */ - Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); + Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); if (use_threadsafe_counters) { IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); - } - else - { + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); /* Update bitmap */ diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index b5fdb3d6..fe43fbe5 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -93,8 +93,8 @@ class AFLLTOPass : public ModulePass { uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - const char *skip_nozero = NULL; - const char *use_threadsafe_counters = nullptr; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; }; @@ -843,9 +843,12 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ if (use_threadsafe_counters) { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } else { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); @@ -861,7 +864,9 @@ bool AFLLTOPass::runOnModule(Module &M) { } IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + ->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + } // done :) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index fe9e2e40..62f8b2ed 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -81,12 +81,12 @@ class AFLCoverage : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t ngram_size = 0; - uint32_t ctx_k = 0; - uint32_t map_size = MAP_SIZE; - uint32_t function_minimum_size = 1; - const char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; - const char * use_threadsafe_counters = nullptr; + uint32_t ngram_size = 0; + uint32_t ctx_k = 0; + uint32_t map_size = MAP_SIZE; + uint32_t function_minimum_size = 1; + const char *ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; }; @@ -188,18 +188,30 @@ bool AFLCoverage::runOnModule(Module &M) { if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { if (use_threadsafe_counters) { - if (!getenv("AFL_LLVM_NOT_ZERO")) { - skip_nozero = "1"; - SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); - } - else { - SAYF(cCYA "afl-llvm-pass" VERSION cRST - " using thread safe not-zero-counters\n"); - } - } - else - { - SAYF(cCYA "afl-llvm-pass" VERSION cRST " using non-thread safe instrumentation\n"); + + // disabled unless there is support for other modules as well + // (increases documentation complexity) + /* if (!getenv("AFL_LLVM_NOT_ZERO")) { */ + + skip_nozero = "1"; + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); + + /* + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using thread safe not-zero-counters\n"); + + } + + */ + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using non-thread safe instrumentation\n"); + } } @@ -649,44 +661,44 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ + if (use_threadsafe_counters) { /* Atomic */ - if (use_threadsafe_counters) {/* Atomic */ - - #if LLVM_VERSION_MAJOR < 9 +#if LLVM_VERSION_MAJOR < 9 if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in llvm is then fixed - #else + NULL) { // with llvm 9 we make this the default as the bug in llvm + // is then fixed +#else if (!skip_nozero) { - #endif +#endif // register MapPtrIdx in a todo list todo.push_back(MapPtrIdx); - } - else - { + } else { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } - } - else - { + + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); Value *Incr = IRB.CreateAdd(Counter, One); - #if LLVM_VERSION_MAJOR < 9 +#if LLVM_VERSION_MAJOR < 9 if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in llvm is - // then fixed - #else + NULL) { // with llvm 9 we make this the default as the bug in llvm + // is then fixed +#else if (!skip_nozero) { - #endif +#endif /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to 1 + * Once this counter reaches its maximum value, it next increments to + * 1 * * Instead of * Counter + 1 -> Counter @@ -705,7 +717,7 @@ bool AFLCoverage::runOnModule(Module &M) { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - } /* non atomic case */ + } /* non atomic case */ /* Update prev_loc history vector (by placing cur_loc at the head of the vector and shuffle the other elements back by one) */ @@ -762,16 +774,19 @@ bool AFLCoverage::runOnModule(Module &M) { } - if (use_threadsafe_counters) { /*Atomic NeverZero */ + if (use_threadsafe_counters) { /*Atomic NeverZero */ // handle the list of registered blocks to instrument for (auto val : todo) { - /* hexcoder: Realize a thread-safe counter that skips zero during overflow. Once this counter reaches its maximum value, it next increments to 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter + + /* hexcoder: Realize a thread-safe counter that skips zero during + * overflow. Once this counter reaches its maximum value, it next + * increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter */ /* equivalent c code looks like this @@ -781,12 +796,19 @@ bool AFLCoverage::runOnModule(Module &M) { int old = atomic_load_explicit(&Counter, memory_order_relaxed); int new; do { + if (old == 255) { + new = 1; + } else { + new = old + 1; + } + } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new, + memory_order_relaxed, memory_order_relaxed)); */ @@ -805,7 +827,8 @@ bool AFLCoverage::runOnModule(Module &M) { BasicBlock *BB = IRB.GetInsertBlock(); // insert a basic block with the corpus of a do while loop - // the calculation may need to repeat, if atomic compare_exchange is not successful + // the calculation may need to repeat, if atomic compare_exchange is not + // successful BasicBlock::iterator it(*Counter); it++; // split after load counter @@ -857,6 +880,7 @@ bool AFLCoverage::runOnModule(Module &M) { // if the cmpXchg was not successful, retry IRB.CreateCondBr(Success, end_bb, do_while_bb); + } } diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index d4742e3e..6ea24f08 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -69,9 +69,8 @@ __attribute__((constructor)) void __libqasan_init() { __libqasan_is_initialized = 1; __libqasan_init_hooks(); - - if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) - __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); diff --git a/src/afl-cc.c b/src/afl-cc.c index 6be6e165..486f7468 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1777,7 +1777,8 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" - " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, " + "disables neverzero\n" COUNTER_BEHAVIOUR diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4a3e7f33..c3ce2edd 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -561,6 +561,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || + afl->queue_cur->favored || !(afl->fsrv.total_execs % afl->queued_paths) || get_cur_time() - afl->last_path_time > 300000) { // 300 seconds diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a3a623d9..5bdb4c8d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2066,13 +2066,10 @@ int main(int argc, char **argv_orig, char **envp) { break; case 4: afl->expand_havoc = 5; - if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = 3; + // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = + // 3; break; case 5: - // if not in sync mode, enable deterministic mode? - // if (!afl->sync_id) afl->skip_deterministic = 0; - afl->expand_havoc = 6; - case 6: // nothing else currently break; -- cgit 1.4.1 From 5b5dff4584f0efa2c02db7d75ebab7e31c253789 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 1 Jun 2021 10:36:18 +0200 Subject: Wording: "never zero" -> NeverZero --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29ea918b..e7344761 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -42,7 +42,7 @@ sending a mail to . - afl-cc: - We do not support llvm versions prior 6.0 anymore - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`), - note that this disables never zero counters. + note that this disables NeverZero counters. - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD -- cgit 1.4.1 From 17e904eedf025e870c79cd0dcc037282e1cce1d7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 10:40:25 +0200 Subject: fix afl_custom_post_process with multiple custom mutators --- docs/Changelog.md | 9 +++++---- src/afl-fuzz-run.c | 30 ++++++++++++------------------ 2 files changed, 17 insertions(+), 22 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index e7344761..09e46fb6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,13 +22,14 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - fixed a bug when trimming for stdin targets - - default cmplog level (-l) is now 2, better efficiency. - - cmplog level 3 (-l 3) now performs redqueen on everything. - use with care. - - better fuzzing strategy yields for enabled options + - cmplog -l: default cmplog level is now 2, better efficiency. + level 3 now performs redqueen on everything. use with care. + - better fuzzing strategy yield display for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - fixed a crash when more than one custom mutator was used together + with afl_custom_post_process - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5a481639..7df4c625 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -107,27 +107,21 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) { new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - } - - new_mem = new_buf; - - }); + if (unlikely(!new_buf && new_size <= 0)) { - if (unlikely(!new_buf && (new_size <= 0))) { - - FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); + FATAL("Custom_post_process failed (ret: %lu)", + (long unsigned)new_size); - } else if (likely(new_buf)) { + } - /* everything as planned. use the new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); + new_mem = new_buf; - } else { + } - /* custom mutators do not has a custom_post_process function */ - afl_fsrv_write_to_testcase(&afl->fsrv, mem, len); + }); - } + /* everything as planned. use the potentially new data. */ + afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); } else { @@ -188,16 +182,16 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - if (unlikely(!new_buf || (new_size <= 0))) { + if (unlikely(!new_buf || new_size <= 0)) { FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); } - } + new_mem = new_buf; - new_mem = new_buf; + } }); -- cgit 1.4.1 From 5f6ff95e6a203ef6392f7c100a981671edc5fe41 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 10:53:02 +0200 Subject: fix docs --- custom_mutators/examples/post_library_gif.so.c | 5 +++-- docs/custom_mutators.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c index ac10f409..aec05720 100644 --- a/custom_mutators/examples/post_library_gif.so.c +++ b/custom_mutators/examples/post_library_gif.so.c @@ -45,6 +45,7 @@ 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` and return the original `len`. + NOTE: the following is currently NOT true, we abort in this case! 2) If you want to skip this test case altogether and have AFL generate a new one, return 0 or set `*out_buf = NULL`. Use this sparingly - it's faster than running the target program @@ -53,14 +54,14 @@ 3) If you want to modify the test case, allocate an appropriately-sized buffer, move the data into that buffer, make the necessary changes, and then return the new pointer as out_buf. Return an appropriate len - afterwards. + afterwards. Note that the buffer will *not* be freed for you. To avoid memory leaks, you need to free it or reuse it on subsequent calls (as shown below). *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - Aight. The example below shows a simple postprocessor that tries to make + Alright. The example below shows a simple postprocessor that tries to make sure that all input files start with "GIF89a". PS. If you don't like C, you can try out the unix-based wrapper from diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 3e3ae01d..129d6676 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -123,6 +123,7 @@ def deinit(): # optional for Python Note that this function is optional - but it makes sense to use it. You would only skip this if `post_process` is used to fix checksums etc. so if you are using it e.g. as a post processing library. + Note that a length > 0 *must* be returned! - `describe` (optional): -- cgit 1.4.1 From d20d03114179e7c1dbd142972cafbf4499978cfc Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 1 Jun 2021 12:14:53 +0200 Subject: Dev (#949) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters Co-authored-by: van Hauser Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic --- README.md | 3 +- custom_mutators/examples/post_library_gif.so.c | 5 +- docs/Changelog.md | 11 +- docs/custom_mutators.md | 1 + docs/env_variables.md | 6 + frida_mode/src/instrument/instrument_debug.c | 2 +- frida_mode/src/persistent/persistent_x64.c | 1 + frida_mode/src/stats/stats.c | 4 +- include/debug.h | 7 +- include/envs.h | 1 + instrumentation/README.llvm.md | 5 + instrumentation/README.neverzero.md | 14 +- instrumentation/SanitizerCoverageLTO.so.cc | 35 +-- instrumentation/SanitizerCoveragePCGUARD.so.cc | 33 ++- instrumentation/afl-llvm-lto-instrumentation.so.cc | 37 ++-- instrumentation/afl-llvm-pass.so.cc | 234 ++++++++++++++++++--- qemu_mode/libqasan/libqasan.c | 5 +- src/afl-cc.c | 2 + src/afl-common.c | 12 +- src/afl-fuzz-one.c | 1 + src/afl-fuzz-redqueen.c | 2 +- src/afl-fuzz-run.c | 30 ++- src/afl-fuzz.c | 7 +- test/test-llvm.sh | 30 +++ 24 files changed, 381 insertions(+), 107 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 69e2d14a..c04dba98 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ behaviours and defaults: | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| + | Threadsafe counters | | x(3) | | | | | | NeverZero | x86[_64]| x(1) | x | x | x | x | | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | @@ -104,7 +105,7 @@ behaviours and defaults: 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin - 3. (currently unassigned) + 3. with `AFL_LLVM_THREADSAFE_INST`, disables NeverZero 4. with pcguard mode and LTO mode for LLVM 11 and newer 5. upcoming, development in the branch 6. not compatible with LTO instrumentation and needs at least LLVM v4.1 diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c index ac10f409..aec05720 100644 --- a/custom_mutators/examples/post_library_gif.so.c +++ b/custom_mutators/examples/post_library_gif.so.c @@ -45,6 +45,7 @@ 1) If you don't want to modify the test case, simply set `*out_buf = in_buf` and return the original `len`. + NOTE: the following is currently NOT true, we abort in this case! 2) If you want to skip this test case altogether and have AFL generate a new one, return 0 or set `*out_buf = NULL`. Use this sparingly - it's faster than running the target program @@ -53,14 +54,14 @@ 3) If you want to modify the test case, allocate an appropriately-sized buffer, move the data into that buffer, make the necessary changes, and then return the new pointer as out_buf. Return an appropriate len - afterwards. + afterwards. Note that the buffer will *not* be freed for you. To avoid memory leaks, you need to free it or reuse it on subsequent calls (as shown below). *** Feel free to reuse the original 'in_buf' BUFFER and return it. *** - Aight. The example below shows a simple postprocessor that tries to make + Alright. The example below shows a simple postprocessor that tries to make sure that all input files start with "GIF89a". PS. If you don't like C, you can try out the unix-based wrapper from diff --git a/docs/Changelog.md b/docs/Changelog.md index 298a3998..09e46fb6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,13 +22,14 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - fixed a bug when trimming for stdin targets - - default cmplog level (-l) is now 2, better efficiency. - - cmplog level 3 (-l 3) now performs redqueen on everything. - use with care. - - better fuzzing strategy yields for enabled options + - cmplog -l: default cmplog level is now 2, better efficiency. + level 3 now performs redqueen on everything. use with care. + - better fuzzing strategy yield display for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - fixed a crash when more than one custom mutator was used together + with afl_custom_post_process - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default @@ -41,6 +42,8 @@ sending a mail to . it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore + - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`), + note that this disables NeverZero counters. - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 3e3ae01d..129d6676 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -123,6 +123,7 @@ def deinit(): # optional for Python Note that this function is optional - but it makes sense to use it. You would only skip this if `post_process` is used to fix checksums etc. so if you are using it e.g. as a post processing library. + Note that a length > 0 *must* be returned! - `describe` (optional): diff --git a/docs/env_variables.md b/docs/env_variables.md index 7bbc0fdd..38a67bc7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,6 +231,12 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. +### Thread safe instrumentation counters (in all modes) + + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread + safe counters. The overhead is a little bit higher compared to the older + non-thread safe case. Note that this disables neverzero (see below). + ### NOT_ZERO - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index be72ef89..f8c1df77 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -17,7 +17,7 @@ static void instrument_debug(char *format, ...) { va_list ap; char buffer[4096] = {0}; int ret; - int len; + int len; va_start(ap, format); ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index 4c495d47..4cb960fc 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -1,3 +1,4 @@ +#include #include "frida-gum.h" #include "config.h" diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 890a8d6b..662fb6d5 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -96,10 +96,10 @@ void stats_init(void) { void stats_vprint(int fd, char *format, va_list ap) { char buffer[4096] = {0}; - int ret; + int ret; int len; - if(vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } len = strnlen(buffer, sizeof(buffer)); IGNORED_RETURN(write(fd, buffer, len)); diff --git a/include/debug.h b/include/debug.h index fc1f39cb..f8df5711 100644 --- a/include/debug.h +++ b/include/debug.h @@ -362,7 +362,12 @@ static inline const char *colorfilter(const char *x) { \ s32 _len = (s32)(len); \ s32 _res = write(_fd, (buf), _len); \ - if (_res != _len) RPFATAL(_res, "Short write to %s, fd %d", fn, _fd); \ + if (_res != _len) { \ + \ + RPFATAL(_res, "Short write to %s, fd %d (%d of %d bytes)", fn, _fd, \ + _res, _len); \ + \ + } \ \ } while (0) diff --git a/include/envs.h b/include/envs.h index 08b3284a..15116fc1 100644 --- a/include/envs.h +++ b/include/envs.h @@ -126,6 +126,7 @@ static char *afl_environment_variables[] = { "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_INSTRUMENT_FILE", + "AFL_LLVM_THREADSAFE_INST", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_TRY_AFFINITY", diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index cfe537d5..8ce5afb9 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,6 +144,11 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) +Support for thread safe counters has been added for all modes. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision +in multi threaded apps for a slightly higher instrumentation overhead. +This also disables the nozero counter default for performance reasons. + ## 4) Snapshot feature To speed up fuzzing you can use a linux loadable kernel module which enables diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md index 49104e00..9bcae324 100644 --- a/instrumentation/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -16,11 +16,12 @@ at a very little cost (one instruction per edge). (The alternative of saturated counters has been tested also and proved to be inferior in terms of path discovery.) -This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is optional if -the llvm version is below 9 - as there is a perfomance bug that is only fixed -in version 9 and onwards. +This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is +optional if multithread safe counters are selected or the llvm version is below +9 - as there are severe performance costs in these cases. -If you want to enable this for llvm versions below 9 then set +If you want to enable this for llvm versions below 9 or thread safe counters +then set ``` export AFL_LLVM_NOT_ZERO=1 @@ -33,3 +34,8 @@ AFL_LLVM_SKIP_NEVERZERO=1 ``` If the target does not have extensive loops or functions that are called a lot then this can give a small performance boost. + +Please note that the default counter implementations are not thread safe! + +Support for thread safe counters in mode LLVM CLASSIC can be activated with setting +`AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 2f4337eb..20f1856e 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -236,7 +236,8 @@ class ModuleSanitizerCoverage { uint32_t inst = 0; uint32_t afl_global_id = 0; uint64_t map_addr = 0; - char * skip_nozero = NULL; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; std::vector BlockList; DenseMap valueMap; std::vector dictionary; @@ -437,6 +438,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL) if ((afl_global_id = atoi(ptr)) < 0) @@ -1208,7 +1210,7 @@ void ModuleSanitizerCoverage::instrumentFunction( return; // Should not instrument sanitizer init functions. if (F.getName().startswith("__sanitizer_")) return; // Don't instrument __sanitizer_* callbacks. - // Don't touch available_externally functions, their actual body is elewhere. + // Don't touch available_externally functions, their actual body is elsewhere. if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return; // Don't instrument MSVC CRT configuration helpers. They may run before normal // initialization. @@ -1495,22 +1497,31 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ + if (use_threadsafe_counters) { /* Atomic */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - Value *Incr = IRB.CreateAdd(Counter, One); + } else { - if (skip_nozero == NULL) { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(Mo->getMDKindID("nosanitize"), + MDNode::get(*Ct, None)); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Tyi); - Incr = IRB.CreateAdd(Incr, carry); + Value *Incr = IRB.CreateAdd(Counter, One); - } + if (skip_nozero == NULL) { - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Tyi); + Incr = IRB.CreateAdd(Incr, carry); + + } + + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + + } // done :) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 8878d3b1..4a8c9e28 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -86,7 +86,8 @@ const char SanCovPCsSectionName[] = "sancov_pcs"; const char SanCovLowestStackName[] = "__sancov_lowest_stack"; -static char *skip_nozero; +static const char *skip_nozero; +static const char *use_threadsafe_counters; namespace { @@ -386,6 +387,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); initInstrumentList(); scanForDangerousFunctions(&M); @@ -1067,22 +1069,31 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, /* Load counter for CurLoc */ - Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); - /* Update bitmap */ + if (use_threadsafe_counters) { - Value *Incr = IRB.CreateAdd(Counter, One); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - if (skip_nozero == NULL) { + } else { - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + /* Update bitmap */ - } + Value *Incr = IRB.CreateAdd(Counter, One); + + if (skip_nozero == NULL) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - IRB.CreateStore(Incr, MapPtrIdx); + } + + IRB.CreateStore(Incr, MapPtrIdx); + + } // done :) diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 68bd2fa5..fe43fbe5 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -93,7 +93,8 @@ class AFLLTOPass : public ModulePass { uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - char * skip_nozero = NULL; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; }; @@ -131,6 +132,8 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) { if ((documentFile = fopen(ptr, "a")) == NULL) @@ -839,22 +842,32 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + if (use_threadsafe_counters) { + + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - Value *Incr = IRB.CreateAdd(Counter, One); + } else { - if (skip_nozero == NULL) { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + Value *Incr = IRB.CreateAdd(Counter, One); - } + if (skip_nozero == NULL) { - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); + + } + + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } // done :) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 0f773aba..a8f1baff 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -81,11 +81,12 @@ class AFLCoverage : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t ngram_size = 0; - uint32_t ctx_k = 0; - uint32_t map_size = MAP_SIZE; - uint32_t function_minimum_size = 1; - char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + uint32_t ngram_size = 0; + uint32_t ctx_k = 0; + uint32_t map_size = MAP_SIZE; + uint32_t function_minimum_size = 1; + const char *ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; }; @@ -182,6 +183,38 @@ bool AFLCoverage::runOnModule(Module &M) { char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + + if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { + + if (use_threadsafe_counters) { + + // disabled unless there is support for other modules as well + // (increases documentation complexity) + /* if (!getenv("AFL_LLVM_NOT_ZERO")) { */ + + skip_nozero = "1"; + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); + + /* + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using thread safe not-zero-counters\n"); + + } + + */ + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using non-thread safe instrumentation\n"); + + } + + } unsigned PrevLocSize = 0; unsigned PrevCallerSize = 0; @@ -388,7 +421,6 @@ bool AFLCoverage::runOnModule(Module &M) { #endif // other constants we need - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); Value * PrevCtx = NULL; // CTX sensitive coverage @@ -410,6 +442,7 @@ bool AFLCoverage::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; + std::list todo; for (auto &BB : F) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); @@ -628,37 +661,68 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + if (use_threadsafe_counters) { /* Atomic */ + /* + #if LLVM_VERSION_MAJOR < 9 + if (neverZero_counters_str != + NULL) { // with llvm 9 we make this the default as the bug + in llvm + // is then fixed + #else + if (!skip_nozero) { + + #endif + // register MapPtrIdx in a todo list + todo.push_back(MapPtrIdx); + + } else { + + */ + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); + /* + + } + + */ - Value *Incr = IRB.CreateAdd(Counter, One); + } else { + + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + Value *Incr = IRB.CreateAdd(Counter, One); #if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in llvm is - // then fixed + if (neverZero_counters_str != + NULL) { // with llvm 9 we make this the default as the bug in llvm + // is then fixed #else - if (!skip_nozero) { + if (!skip_nozero) { #endif - /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter - */ + /* hexcoder: Realize a counter that skips zero during overflow. + * Once this counter reaches its maximum value, it next increments to + * 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter + */ + + ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + } - } + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + } /* non atomic case */ /* Update prev_loc history vector (by placing cur_loc at the head of the vector and shuffle the other elements back by one) */ @@ -715,6 +779,120 @@ bool AFLCoverage::runOnModule(Module &M) { } +#if 0 + if (use_threadsafe_counters) { /*Atomic NeverZero */ + // handle the list of registered blocks to instrument + for (auto val : todo) { + + /* hexcoder: Realize a thread-safe counter that skips zero during + * overflow. Once this counter reaches its maximum value, it next + * increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter + */ + + /* equivalent c code looks like this + * Thanks to + https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ + + int old = atomic_load_explicit(&Counter, memory_order_relaxed); + int new; + do { + + if (old == 255) { + + new = 1; + + } else { + + new = old + 1; + + } + + } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new, + + memory_order_relaxed, memory_order_relaxed)); + + */ + + Value * MapPtrIdx = val; + Instruction * MapPtrIdxInst = cast(val); + BasicBlock::iterator it0(&(*MapPtrIdxInst)); + ++it0; + IRBuilder<> IRB(&(*it0)); + + // load the old counter value atomically + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setAlignment(llvm::Align()); + Counter->setAtomic(llvm::AtomicOrdering::Monotonic); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + BasicBlock *BB = IRB.GetInsertBlock(); + // insert a basic block with the corpus of a do while loop + // the calculation may need to repeat, if atomic compare_exchange is not + // successful + + BasicBlock::iterator it(*Counter); + it++; // split after load counter + BasicBlock *end_bb = BB->splitBasicBlock(it); + end_bb->setName("injected"); + + // insert the block before the second half of the split + BasicBlock *do_while_bb = + BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + + // set terminator of BB from target end_bb to target do_while_bb + auto term = BB->getTerminator(); + BranchInst::Create(do_while_bb, BB); + term->eraseFromParent(); + + // continue to fill instructions into the do_while loop + IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); + + PHINode *PN = IRB.CreatePHI(Int8Ty, 2); + + // compare with maximum value 0xff + auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + + // increment the counter + Value *Incr = IRB.CreateAdd(Counter, One); + + // select the counter value or 1 + auto *Select = IRB.CreateSelect(Cmp, One, Incr); + + // try to save back the new counter value + auto *CmpXchg = IRB.CreateAtomicCmpXchg( + MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic, + llvm::AtomicOrdering::Monotonic); + CmpXchg->setAlignment(llvm::Align()); + CmpXchg->setWeak(true); + CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + // get the result of trying to update the Counter + Value *Success = + IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); + // get the (possibly updated) value of Counter + Value *OldVal = + IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); + + // initially we use Counter + PN->addIncoming(Counter, BB); + // on retry, we use the updated value + PN->addIncoming(OldVal, do_while_bb); + + // if the cmpXchg was not successful, retry + IRB.CreateCondBr(Success, end_bb, do_while_bb); + + } + + } + +#endif + } /* diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index d4742e3e..6ea24f08 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -69,9 +69,8 @@ __attribute__((constructor)) void __libqasan_init() { __libqasan_is_initialized = 1; __libqasan_init_hooks(); - - if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) - __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); diff --git a/src/afl-cc.c b/src/afl-cc.c index 8af8e7b0..486f7468 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1777,6 +1777,8 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, " + "disables neverzero\n" COUNTER_BEHAVIOUR diff --git a/src/afl-common.c b/src/afl-common.c index 8826de70..c61ce3d8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -479,9 +479,17 @@ void print_suggested_envs(char *mispelled_env) { size_t end = start + strcspn(afl_env + start, "_") + 1; memcpy(reduced, afl_env, start); - if (end < afl_env_len) + if (end < afl_env_len) { + memcpy(reduced + start, afl_env + end, afl_env_len - end); - reduced[afl_env_len - end + start] = 0; + + } + + if (afl_env_len + start >= end) { + + reduced[afl_env_len - end + start] = 0; + + } int distance = string_distance_levenshtein(reduced, env_name); if (distance < ENV_SIMILARITY_TRESHOLD && seen[j] == 0) { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4a3e7f33..c3ce2edd 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -561,6 +561,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || + afl->queue_cur->favored || !(afl->fsrv.total_execs % afl->queued_paths) || get_cur_time() - afl->last_path_time > 300000) { // 300 seconds diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index cf1e5ea5..22fd0621 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -438,7 +438,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, if (taint) { if (afl->colorize_success && afl->cmplog_lvl < 3 && - (len / positions == 1 && positions > CMPLOG_POSITIONS_MAX && + (positions > CMPLOG_POSITIONS_MAX && len / positions == 1 && afl->active_paths / afl->colorize_success > CMPLOG_CORPUS_PERCENT)) { #ifdef _DEBUG diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5a481639..2c3e8a1b 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -107,27 +107,21 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) { new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - } - - new_mem = new_buf; - - }); + if (unlikely(!new_buf && new_size <= 0)) { - if (unlikely(!new_buf && (new_size <= 0))) { - - FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); + FATAL("Custom_post_process failed (ret: %lu)", + (long unsigned)new_size); - } else if (likely(new_buf)) { + } - /* everything as planned. use the new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); + new_mem = new_buf; - } else { + } - /* custom mutators do not has a custom_post_process function */ - afl_fsrv_write_to_testcase(&afl->fsrv, mem, len); + }); - } + /* everything as planned. use the potentially new data. */ + afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); } else { @@ -188,16 +182,16 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - if (unlikely(!new_buf || (new_size <= 0))) { + if (unlikely(!new_buf || new_size <= 0)) { FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); } - } + new_mem = new_buf; - new_mem = new_buf; + } }); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a3a623d9..5bdb4c8d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2066,13 +2066,10 @@ int main(int argc, char **argv_orig, char **envp) { break; case 4: afl->expand_havoc = 5; - if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = 3; + // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = + // 3; break; case 5: - // if not in sync mode, enable deterministic mode? - // if (!afl->sync_id) afl->skip_deterministic = 0; - afl->expand_havoc = 6; - case 6: // nothing else currently break; diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 06d0a0f8..1152cc4e 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -43,6 +43,36 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { $ECHO "$RED[!] llvm_mode failed" CODE=1 } + AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_THREADSAFE_INST=1 ../afl-clang-fast -o test-instr.ts ../test-instr.c > /dev/null 2>&1 + test -e test-instr.ts && { + $ECHO "$GREEN[+] llvm_mode threadsafe compilation succeeded" + echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.0 -r -- ./test-instr.ts > /dev/null 2>&1 + AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.1 -r -- ./test-instr.ts < /dev/null > /dev/null 2>&1 + test -e test-instr.ts.0 -a -e test-instr.ts.1 && { + diff test-instr.ts.0 test-instr.ts.1 > /dev/null 2>&1 && { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation should be different on different input but is not" + CODE=1 + } || { + $ECHO "$GREEN[+] llvm_mode threadsafe instrumentation present and working correctly" + TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.ts 2>&1 | grep Captur | awk '{print$3}'` + test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && { + $ECHO "$GREEN[+] llvm_mode run reported $TUPLES threadsafe instrumented locations which is fine" + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation produces weird numbers: $TUPLES" + CODE=1 + } + test "$TUPLES" -lt 3 && SKIP=1 + true + } + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed" + CODE=1 + } + rm -f test-instr.ts.0 test-instr.ts.1 + } || { + $ECHO "$RED[!] llvm_mode (threadsafe) failed" + CODE=1 + } ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1 test -e test-instr.so && { $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded" -- cgit 1.4.1 From f9ca2cf98938ae382d0affc47dbbc78d7291708b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 12:15:14 +0200 Subject: v3.13c release --- README.md | 4 ++-- docs/Changelog.md | 2 +- include/config.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index c04dba98..ba612edb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AFL++ Logo - Release Version: [3.12c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.13a + Github Version: 3.14a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 09e46fb6..1887c099 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,7 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++3.13a (development) +### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. diff --git a/include/config.h b/include/config.h index 80cdb684..a1fdd789 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13a" +#define VERSION "++3.13c" /****************************************************** * * -- cgit 1.4.1 From 02294d368a29a0e748ab00c240d56c2c225b0941 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 1 Jun 2021 12:15:54 +0200 Subject: v3.13c release (#950) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic --- README.md | 4 ++-- docs/Changelog.md | 2 +- include/config.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index c04dba98..ba612edb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AFL++ Logo - Release Version: [3.12c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.13a + Github Version: 3.14a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 09e46fb6..1887c099 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,7 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++3.13a (development) +### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. diff --git a/include/config.h b/include/config.h index 80cdb684..a1fdd789 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13a" +#define VERSION "++3.13c" /****************************************************** * * -- cgit 1.4.1 From bdc7aa1a94b04de1e670f42eaa329bc18826cb9d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 12:39:13 +0200 Subject: v3.14a init --- docs/Changelog.md | 4 ++++ include/config.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 1887c099..419d5a99 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,10 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.14a (release) + - ... your pull request? + + ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, diff --git a/include/config.h b/include/config.h index a1fdd789..9d732e53 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13c" +#define VERSION "++3.14a" /****************************************************** * * -- cgit 1.4.1 From 409636079118cb3e2c864bf2729ebb07bc0437ee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 12:48:10 +0200 Subject: update MacOS Install information --- docs/INSTALL.md | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 80d452f7..fc57f546 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -65,22 +65,17 @@ The QEMU mode is currently supported only on Linux. I think it's just a QEMU problem, I couldn't get a vanilla copy of user-mode emulation support working correctly on BSD at all. -## 3. MacOS X on x86 +## 3. MacOS X on x86 and arm64 (M1) MacOS X should work, but there are some gotchas due to the idiosyncrasies of the platform. On top of this, I have limited release testing capabilities and depend mostly on user feedback. -To build AFL, install Xcode and follow the general instructions for Linux. +To build AFL, install llvm (and perhaps gcc) from brew and follow the general +instructions for Linux. If possible avoid Xcode at all cost. -The Xcode 'gcc' tool is just a wrapper for clang, so be sure to use afl-clang -to compile any instrumented binaries; afl-gcc will fail unless you have GCC -installed from another source (in which case, please specify `AFL_CC` and -`AFL_CXX` to point to the "real" GCC binaries). - -Only 64-bit compilation will work on the platform; porting the 32-bit -instrumentation would require a fair amount of work due to the way OS X -handles relocations, and today, virtually all MacOS X boxes are 64-bit. +afl-gcc will fail unless you have GCC installed, but that is using outdated +instrumentation anyway. You don't want that. The crash reporting daemon that comes by default with MacOS X will cause problems with fuzzing. You need to turn it off by following the instructions @@ -98,10 +93,7 @@ and definitely don't look POSIX-compliant. This means two things: User emulation mode of QEMU does not appear to be supported on MacOS X, so black-box instrumentation mode (`-Q`) will not work. - -The llvm instrumentation requires a fully-operational installation of clang. The one that -comes with Xcode is missing some of the essential headers and helper tools. -See README.llvm.md for advice on how to build the compiler from scratch. +However Frida mode (`-O`) should work on x86 and arm64 MacOS boxes. MacOS X supports SYSV shared memory used by AFL's instrumentation, but the default settings aren't usable with AFL++. The default settings on 10.14 seem -- cgit 1.4.1 From bee3902062a7020218533476e006d9d438d75406 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 18:44:52 +0200 Subject: add fix info --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 419d5a99..a49c0672 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.14a (release) - - ... your pull request? + - Fix for llvm 13 ### Version ++3.13c (release) -- cgit 1.4.1 From a321d4102b6c3bec3471c4351692d1ad2a410e70 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 1 Jun 2021 18:55:25 +0200 Subject: push to stable (#953) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release * back push (#952) * Dev (#949) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters Co-authored-by: van Hauser Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic * v3.13c release (#950) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder- * v3.14a init * remove redundant unsetenv (#947) * update MacOS Install information * add missing clean action for frida_mode * ensure memory is there before free * adapt to incompatible LLVM 13 API * fix stupid typos * add fix info Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: terrynini --- GNUmakefile | 1 + docs/Changelog.md | 4 ++++ docs/INSTALL.md | 20 ++++++-------------- include/config.h | 2 +- instrumentation/SanitizerCoverageLTO.so.cc | 3 +++ instrumentation/SanitizerCoveragePCGUARD.so.cc | 3 +++ instrumentation/afl-llvm-lto-instrumentation.so.cc | 3 +++ instrumentation/afl-llvm-pass.so.cc | 3 +++ src/afl-fuzz-redqueen.c | 7 ++++++- src/afl-fuzz-run.c | 1 - src/afl-fuzz.c | 3 --- 11 files changed, 30 insertions(+), 20 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index 270746b4..a45f6d5c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -572,6 +572,7 @@ clean: $(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/libcompcov clean $(MAKE) -C qemu_mode/libqasan clean + $(MAKE) -C frida_mode clean ifeq "$(IN_REPO)" "1" test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true diff --git a/docs/Changelog.md b/docs/Changelog.md index 1887c099..a49c0672 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,10 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.14a (release) + - Fix for llvm 13 + + ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 80d452f7..fc57f546 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -65,22 +65,17 @@ The QEMU mode is currently supported only on Linux. I think it's just a QEMU problem, I couldn't get a vanilla copy of user-mode emulation support working correctly on BSD at all. -## 3. MacOS X on x86 +## 3. MacOS X on x86 and arm64 (M1) MacOS X should work, but there are some gotchas due to the idiosyncrasies of the platform. On top of this, I have limited release testing capabilities and depend mostly on user feedback. -To build AFL, install Xcode and follow the general instructions for Linux. +To build AFL, install llvm (and perhaps gcc) from brew and follow the general +instructions for Linux. If possible avoid Xcode at all cost. -The Xcode 'gcc' tool is just a wrapper for clang, so be sure to use afl-clang -to compile any instrumented binaries; afl-gcc will fail unless you have GCC -installed from another source (in which case, please specify `AFL_CC` and -`AFL_CXX` to point to the "real" GCC binaries). - -Only 64-bit compilation will work on the platform; porting the 32-bit -instrumentation would require a fair amount of work due to the way OS X -handles relocations, and today, virtually all MacOS X boxes are 64-bit. +afl-gcc will fail unless you have GCC installed, but that is using outdated +instrumentation anyway. You don't want that. The crash reporting daemon that comes by default with MacOS X will cause problems with fuzzing. You need to turn it off by following the instructions @@ -98,10 +93,7 @@ and definitely don't look POSIX-compliant. This means two things: User emulation mode of QEMU does not appear to be supported on MacOS X, so black-box instrumentation mode (`-Q`) will not work. - -The llvm instrumentation requires a fully-operational installation of clang. The one that -comes with Xcode is missing some of the essential headers and helper tools. -See README.llvm.md for advice on how to build the compiler from scratch. +However Frida mode (`-O`) should work on x86 and arm64 MacOS boxes. MacOS X supports SYSV shared memory used by AFL's instrumentation, but the default settings aren't usable with AFL++. The default settings on 10.14 seem diff --git a/include/config.h b/include/config.h index a1fdd789..9d732e53 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13c" +#define VERSION "++3.14a" /****************************************************** * * diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 20f1856e..372af003 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1500,6 +1500,9 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (use_threadsafe_counters) { /* Atomic */ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, +#if LLVM_VERSION_MAJOR >= 13 + llvm::MaybeAlign(1), +#endif llvm::AtomicOrdering::Monotonic); } else { diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 4a8c9e28..48ad2d02 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1074,6 +1074,9 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (use_threadsafe_counters) { IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, +#if LLVM_VERSION_MAJOR >= 13 + llvm::MaybeAlign(1), +#endif llvm::AtomicOrdering::Monotonic); } else { diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index fe43fbe5..bb9b9279 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -845,6 +845,9 @@ bool AFLLTOPass::runOnModule(Module &M) { if (use_threadsafe_counters) { IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, +#if LLVM_VERSION_MAJOR >= 13 + llvm::MaybeAlign(1), +#endif llvm::AtomicOrdering::Monotonic); } else { diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index a8f1baff..6fe34ccd 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -679,6 +679,9 @@ bool AFLCoverage::runOnModule(Module &M) { */ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, +#if LLVM_VERSION_MAJOR >= 13 + llvm::MaybeAlign(1), +#endif llvm::AtomicOrdering::Monotonic); /* diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 22fd0621..b41ffa88 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -2663,7 +2663,12 @@ exit_its: afl->queue_cur->colorized = CMPLOG_LVL_MAX; - ck_free(afl->queue_cur->cmplog_colorinput); + if (afl->queue_cur->cmplog_colorinput) { + + ck_free(afl->queue_cur->cmplog_colorinput); + + } + while (taint) { t = taint->next; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 2c3e8a1b..493735ff 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -333,7 +333,6 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) { - unsetenv(SHM_FUZZ_ENV_VAR); afl_shm_deinit(afl->shm_fuzz); ck_free(afl->shm_fuzz); afl->shm_fuzz = NULL; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5bdb4c8d..196547f4 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2283,13 +2283,10 @@ stop_fuzzing: destroy_queue(afl); destroy_extras(afl); destroy_custom_mutators(afl); - unsetenv(SHM_ENV_VAR); - unsetenv(CMPLOG_SHM_ENV_VAR); afl_shm_deinit(&afl->shm); if (afl->shm_fuzz) { - unsetenv(SHM_FUZZ_ENV_VAR); afl_shm_deinit(afl->shm_fuzz); ck_free(afl->shm_fuzz); -- cgit 1.4.1 From a38aafc5d0cb9ccf75f99613f52fd0938f5f86c0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 2 Jun 2021 10:50:04 +0200 Subject: fix -F with slash option --- docs/Changelog.md | 3 +++ src/afl-fuzz-init.c | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index a49c0672..a4c6ac10 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,9 @@ sending a mail to . ### Version ++3.14a (release) - Fix for llvm 13 + - afl-fuzz: + - fix -F when a '/' was part of the parameter + - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 88b5bc02..872e3a32 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -480,13 +480,22 @@ void read_foreign_testcases(afl_state_t *afl, int first) { for (iter = 0; iter < afl->foreign_sync_cnt; iter++) { - if (afl->foreign_syncs[iter].dir != NULL && - afl->foreign_syncs[iter].dir[0] != 0) { + if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) { if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); time_t mtime_max = 0; - u8 * name = strrchr(afl->foreign_syncs[iter].dir, '/'); - if (!name) { name = afl->foreign_syncs[iter].dir; } + + u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/'); + if (!name) { + + name = afl->foreign_syncs[iter].dir; + + } else { + + ++name; + + } + if (!strcmp(name, "queue") || !strcmp(name, "out") || !strcmp(name, "default")) { -- cgit 1.4.1 From 70a2077107aac3a226e16731abc8028bcfa61466 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 4 Jun 2021 01:03:54 +0200 Subject: move link --- README.md | 2 +- docs/binaryonly_fuzzing.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 7ee56786..383d71c4 100644 --- a/README.md +++ b/README.md @@ -801,7 +801,7 @@ Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, [Zafl](https://git.zephyr-software.com/opensrc/zafl), etc. +use a binary rewriter like afl-dyninst, retrowrite, zafl, etc. For Qemu and Frida mode, check out the persistent mode, it gives a huge speed improvement if it is possible to use. diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 11e1dbeb..3b32f5ed 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -122,7 +122,7 @@ [https://github.com/vanhauser-thc/afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) -## RETROWRITE +## RETROWRITE, ZAFL, ... other binary rewriter If you have an x86/x86_64 binary that still has its symbols, is compiled with position independant code (PIC/PIE) and does not use most of the C++ @@ -131,6 +131,7 @@ It is at about 80-85% performance. + [https://git.zephyr-software.com/opensrc/zafl](https://git.zephyr-software.com/opensrc/zafl) [https://github.com/HexHive/retrowrite](https://github.com/HexHive/retrowrite) -- cgit 1.4.1 From 0897377b13c42ccdf94963e24738e3deabe85ffa Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 4 Jun 2021 09:21:30 +0200 Subject: add known frontends for supported compiler infrastructures --- docs/ideas.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs') diff --git a/docs/ideas.md b/docs/ideas.md index e25d3ba6..98231ad3 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -34,6 +34,12 @@ Mentor: any Other programming languages also use llvm hence they could (easily?) supported for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ... +GCC also supports: Objective-C, Fortran, Ada, Go, and D +(according to [Gcc homepage](https://gcc.gnu.org/)) + +LLVM also supports: LLGo (Go), kaleidoscope (Haskell), flang (Fortran), emscripten (JavaScript, WASM), ilwasm (CIL (C#)) +(according to [LLVM frontends](https://gist.github.com/axic/62d66fb9d8bccca6cc48fa9841db9241)) + Mentor: vanhauser-thc ## Machine Learning -- cgit 1.4.1 From f3b1c5c382b95f93a20f507b492c396a6284518c Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 4 Jun 2021 09:24:30 +0200 Subject: add Rust --- docs/ideas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/ideas.md b/docs/ideas.md index 98231ad3..0ee69851 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -37,7 +37,7 @@ for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ... GCC also supports: Objective-C, Fortran, Ada, Go, and D (according to [Gcc homepage](https://gcc.gnu.org/)) -LLVM also supports: LLGo (Go), kaleidoscope (Haskell), flang (Fortran), emscripten (JavaScript, WASM), ilwasm (CIL (C#)) +LLVM is also used by: Rust, LLGo (Go), kaleidoscope (Haskell), flang (Fortran), emscripten (JavaScript, WASM), ilwasm (CIL (C#)) (according to [LLVM frontends](https://gist.github.com/axic/62d66fb9d8bccca6cc48fa9841db9241)) Mentor: vanhauser-thc -- cgit 1.4.1 From a5ff9f1bebfc974a774bba896e51e18288f66c68 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 09:02:33 +0200 Subject: remove -D from -M --- docs/Changelog.md | 1 + src/afl-fuzz.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index a4c6ac10..b70ba022 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,6 +12,7 @@ sending a mail to . - Fix for llvm 13 - afl-fuzz: - fix -F when a '/' was part of the parameter + - removed implied -D determinstic from -M main - ensure afl-compiler-rt is built for gcc_module diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 196547f4..dc594b30 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -575,7 +575,6 @@ int main(int argc, char **argv_orig, char **envp) { } afl->sync_id = ck_strdup(optarg); - afl->skip_deterministic = 0; // force deterministic fuzzing afl->old_seed_selection = 1; // force old queue walking seed selection afl->disable_trim = 1; // disable trimming -- cgit 1.4.1 From 4bf08566caccc950e9281474153ee1e3b1984179 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 11:22:07 +0200 Subject: add changelog entry --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index b70ba022..3e79103a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,8 @@ sending a mail to . - afl-fuzz: - fix -F when a '/' was part of the parameter - removed implied -D determinstic from -M main + - if the target becomes unavailable check out out/default/error.txt for + an indicator why - ensure afl-compiler-rt is built for gcc_module -- cgit 1.4.1 From c69edc2b3cc6c9d58c1d10385555817d6d1c43b0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 11:23:58 +0200 Subject: add changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3e79103a..a2c523b0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,8 @@ sending a mail to . - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why + - afl-cc + - support partial linking - ensure afl-compiler-rt is built for gcc_module -- cgit 1.4.1 From 63ee9df54f3c9db8ecbb0fb6186ea912200d9126 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 20:49:23 +0200 Subject: Forkserver for afl-analyze (#963) * afl-analyze forkserver * added missing vars to forkserver * synchronized a bit more with afl-tmin * more debugging, runs now, but need to suppress target output * fix dev/null setting * afl-analyze info: Co-authored-by: hexcoder- --- GNUmakefile | 4 +- docs/Changelog.md | 3 +- src/afl-analyze.c | 235 +++++++++++++++++++----------------------------------- 3 files changed, 84 insertions(+), 158 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index 6df7ea1d..bd206af0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -436,8 +436,8 @@ afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-fork afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) -afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS) +afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS) afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) diff --git a/docs/Changelog.md b/docs/Changelog.md index a2c523b0..a8ed4d72 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,8 +18,7 @@ sending a mail to . - afl-cc - support partial linking - ensure afl-compiler-rt is built for gcc_module - - + - afl-analyze now uses the forkserver for increased performance ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, diff --git a/src/afl-analyze.c b/src/afl-analyze.c index d43278b9..606254d9 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -55,12 +55,7 @@ #include #include -static s32 child_pid; /* PID of the tested program */ - -static u8 *trace_bits; /* SHM with instrumentation bitmap */ - -static u8 *in_file, /* Analyzer input test case */ - *prog_in; /* Targeted program input file */ +static u8 *in_file; /* Analyzer input test case */ static u8 *in_data; /* Input data for analysis */ @@ -73,20 +68,19 @@ static u64 orig_cksum; /* Original checksum */ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ -static s32 dev_null_fd = -1; /* FD to /dev/null */ - static bool edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = true; /* Use stdin for program input? */ -static volatile u8 stop_soon, /* Ctrl-C pressed? */ - child_timed_out; /* Child timed out? */ +static volatile u8 stop_soon; /* Ctrl-C pressed? */ static u8 *target_path; static u8 frida_mode; static u8 qemu_mode; static u32 map_size = MAP_SIZE; +static afl_forkserver_t fsrv = {0}; /* The forkserver */ + /* Constants used for describing byte behavior. */ #define RESP_NONE 0x00 /* Changing byte is a no-op. */ @@ -156,7 +150,7 @@ static void classify_counts(u8 *mem) { static inline u8 anything_set(void) { - u32 *ptr = (u32 *)trace_bits; + u32 *ptr = (u32 *)fsrv.trace_bits; u32 i = (map_size >> 2); while (i--) { @@ -173,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(prog_in); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -205,128 +199,29 @@ static void read_initial_file(void) { } -/* Write output file. */ - -static s32 write_to_file(u8 *path, u8 *mem, u32 len) { - - s32 ret; - - unlink(path); /* Ignore errors */ - - ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - - if (ret < 0) { PFATAL("Unable to create '%s'", path); } - - ck_write(ret, mem, len, path); - - lseek(ret, 0, SEEK_SET); - - return ret; - -} - -/* Handle timeout signal. */ - -static void handle_timeout(int sig) { - - (void)sig; - - child_timed_out = 1; - - if (child_pid > 0) kill(child_pid, SIGKILL); - -} - /* Execute target application. Returns exec checksum, or 0 if program times out. */ -static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { - - static struct itimerval it; - int status = 0; - - s32 prog_in_fd; - u64 cksum; - - memset(trace_bits, 0, map_size); - MEM_BARRIER(); - - prog_in_fd = write_to_file(prog_in, mem, len); - - child_pid = fork(); - - if (child_pid < 0) { PFATAL("fork() failed"); } - - if (!child_pid) { - - struct rlimit r; - - if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 || - dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) { - - *(u32 *)trace_bits = EXEC_FAIL_SIG; - PFATAL("dup2() failed"); - - } - - close(dev_null_fd); - close(prog_in_fd); - - if (mem_limit) { +static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) { - r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + afl_fsrv_write_to_testcase(&fsrv, mem, len); + fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon); -#ifdef RLIMIT_AS + if (ret == FSRV_RUN_ERROR) { - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + FATAL("Error in forkserver"); -#else - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ - -#endif /* ^RLIMIT_AS */ - - } + } else if (ret == FSRV_RUN_NOINST) { - r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + FATAL("Target not instrumented"); - execv(target_path, argv); + } else if (ret == FSRV_RUN_NOBITS) { - *(u32 *)trace_bits = EXEC_FAIL_SIG; - exit(0); + FATAL("Failed to run target"); } - close(prog_in_fd); - - /* Configure timeout, wait for child, cancel timeout. */ - - child_timed_out = 0; - it.it_value.tv_sec = (exec_tmout / 1000); - it.it_value.tv_usec = (exec_tmout % 1000) * 1000; - - setitimer(ITIMER_REAL, &it, NULL); - - if (waitpid(child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); } - - child_pid = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - MEM_BARRIER(); - - /* Clean up bitmap, analyze exit condition, etc. */ - - if (*(u32 *)trace_bits == EXEC_FAIL_SIG) { - - FATAL("Unable to execute '%s'", argv[0]); - - } - - classify_counts(trace_bits); + classify_counts(fsrv.trace_bits); total_execs++; if (stop_soon) { @@ -338,21 +233,19 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { /* Always discard inputs that time out. */ - if (child_timed_out) { + if (fsrv.last_run_timed_out) { exec_hangs++; return 0; } - cksum = hash64(trace_bits, map_size, HASH_CONST); + u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST); - /* We don't actually care if the target is crashing or not, - except that when it does, the checksum should be different. */ + if (ret == FSRV_RUN_CRASH) { - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status))) { + /* We don't actually care if the target is crashing or not, + except that when it does, the checksum should be different. */ cksum ^= 0xffffffff; @@ -616,7 +509,7 @@ static void dump_hex(u32 len, u8 *b_data) { /* Actually analyze! */ -static void analyze(char **argv) { +static void analyze() { u32 i; u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0; @@ -642,16 +535,16 @@ static void analyze(char **argv) { code. */ in_data[i] ^= 0xff; - xor_ff = analyze_run_target(argv, in_data, in_len, 0); + xor_ff = analyze_run_target(in_data, in_len, 0); in_data[i] ^= 0xfe; - xor_01 = analyze_run_target(argv, in_data, in_len, 0); + xor_01 = analyze_run_target(in_data, in_len, 0); in_data[i] = (in_data[i] ^ 0x01) - 0x10; - sub_10 = analyze_run_target(argv, in_data, in_len, 0); + sub_10 = analyze_run_target(in_data, in_len, 0); in_data[i] += 0x20; - add_10 = analyze_run_target(argv, in_data, in_len, 0); + add_10 = analyze_run_target(in_data, in_len, 0); in_data[i] -= 0x10; /* Classify current behavior. */ @@ -724,7 +617,7 @@ static void handle_stop_sig(int sig) { (void)sig; stop_soon = 1; - if (child_pid > 0) { kill(child_pid, SIGKILL); } + afl_fsrv_killall(); } @@ -736,10 +629,10 @@ static void set_up_environment(char **argv) { char *afl_preload; char *frida_afl_preload = NULL; - dev_null_fd = open("/dev/null", O_RDWR); - if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + fsrv.dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - if (!prog_in) { + if (!fsrv.out_file) { u8 *use_dir = "."; @@ -750,10 +643,15 @@ static void set_up_environment(char **argv) { } - prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } + unlink(fsrv.out_file); + fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + + if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } + /* Set sane defaults... */ x = get_afl_env("ASAN_OPTIONS"); @@ -916,11 +814,6 @@ static void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - } /* Display usage hints. */ @@ -982,6 +875,8 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); + afl_fsrv_init(&fsrv); + while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) { switch (opt) { @@ -994,9 +889,9 @@ int main(int argc, char **argv_orig, char **envp) { case 'f': - if (prog_in) { FATAL("Multiple -f options not supported"); } - use_stdin = 0; - prog_in = optarg; + if (fsrv.out_file) { FATAL("Multiple -f options not supported"); } + fsrv.use_stdin = 0; + fsrv.out_file = ck_strdup(optarg); break; case 'e': @@ -1017,6 +912,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!strcmp(optarg, "none")) { mem_limit = 0; + fsrv.mem_limit = 0; break; } @@ -1055,6 +951,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.mem_limit = mem_limit; + } break; @@ -1074,6 +972,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.exec_tmout = exec_tmout; + break; case 'O': /* FRIDA mode */ @@ -1081,6 +981,7 @@ int main(int argc, char **argv_orig, char **envp) { if (frida_mode) { FATAL("Multiple -O options not supported"); } frida_mode = 1; + fsrv.frida_mode = frida_mode; break; @@ -1090,6 +991,8 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; } qemu_mode = 1; + fsrv.mem_limit = mem_limit; + fsrv.qemu_mode = qemu_mode; break; case 'U': @@ -1098,6 +1001,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; } unicorn_mode = 1; + fsrv.mem_limit = mem_limit; break; case 'W': /* Wine+QEMU mode */ @@ -1107,6 +1011,8 @@ int main(int argc, char **argv_orig, char **envp) { use_wine = 1; if (!mem_limit_given) { mem_limit = 0; } + fsrv.qemu_mode = qemu_mode; + fsrv.mem_limit = mem_limit; break; @@ -1125,6 +1031,7 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file) { usage(argv[0]); } map_size = get_map_size(); + fsrv.map_size = map_size; use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX"); @@ -1134,14 +1041,15 @@ int main(int argc, char **argv_orig, char **envp) { /* initialize cmplog_mode */ shm.cmplog_mode = 0; - trace_bits = afl_shm_init(&shm, map_size, 0); + atexit(at_exit_handler); setup_signal_handlers(); set_up_environment(argv); - target_path = find_binary(argv[optind]); - detect_file_args(argv + optind, prog_in, &use_stdin); + fsrv.target_path = find_binary(argv[optind]); + fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); + detect_file_args(argv + optind, fsrv.out_file, &use_stdin); if (qemu_mode) { @@ -1165,14 +1073,31 @@ int main(int argc, char **argv_orig, char **envp) { SAYF("\n"); + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { + + s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); + if (forksrv_init_tmout < 1) { + + FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); + + } + + fsrv.init_tmout = (u32)forksrv_init_tmout; + + } + + fsrv.kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + read_initial_file(); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", mem_limit, exec_tmout, edges_only ? ", edges only" : ""); - analyze_run_target(use_argv, in_data, in_len, 1); + afl_fsrv_start(&fsrv, use_argv, &stop_soon, false); + analyze_run_target(in_data, in_len, 1); - if (child_timed_out) { + if (fsrv.last_run_timed_out) { FATAL("Target binary times out (adjusting -t may help)."); @@ -1184,13 +1109,15 @@ int main(int argc, char **argv_orig, char **envp) { } - analyze(use_argv); + analyze(); OKF("We're done here. Have a nice day!\n"); - if (target_path) { ck_free(target_path); } - afl_shm_deinit(&shm); + afl_fsrv_deinit(&fsrv); + if (fsrv.target_path) { ck_free(fsrv.target_path); } + if (in_data) { ck_free(in_data); } + exit(0); -- cgit 1.4.1 From d64dd7a952de20b693ed1a44063d409a15bbff76 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 22:37:06 +0200 Subject: proper newlines --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index a8ed4d72..103f5920 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,6 +19,8 @@ sending a mail to . - support partial linking - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance + + ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, -- cgit 1.4.1 From fff8c5e0a855eb26408a555758ebe29044b047cd Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 8 Jun 2021 09:56:11 +0200 Subject: adapt docs to minimum LLVM version --- README.md | 4 ++-- docs/Changelog.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 383d71c4..bc547b3c 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. @@ -296,7 +296,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 3.8+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ diff --git a/docs/Changelog.md b/docs/Changelog.md index 103f5920..6c851460 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,9 @@ sending a mail to . an indicator why - afl-cc - support partial linking + - We do support llvm versions from 3.8 again + - afl_analyze + - fix timeout handling and support forkserver - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance -- cgit 1.4.1 From 48c878a76ddec2c133fd5708b185b2ac27740084 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 8 Jun 2021 10:10:42 +0200 Subject: push to stable (#962) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release * back push (#952) * Dev (#949) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters Co-authored-by: van Hauser Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic * v3.13c release (#950) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder- * v3.14a init * remove redundant unsetenv (#947) * update MacOS Install information * add missing clean action for frida_mode * ensure memory is there before free * adapt to incompatible LLVM 13 API * fix stupid typos * add fix info * build afl-compiler-rt even with broken llvm * fix -F with slash option * dynamic_list and afl-compiler-rt rework * detect partial linking in afl-cc * partial linking with -Wl * Add proper name and URL for Zafl (#959) * move link * add known frontends for supported compiler infrastructures * add Rust * fix ui fuzzing stage index (#960) * fix overflowing UI fields 'now processing' * restored timeout handling (with SIGALRM for now) * On non-Linux systems make clean may fail for frida_mode * give hint how to set env var for path to llvm-config tool * setting AFL_CC for test-llvm.sh on FreeBSD is not necessary anymore * remove -D from -M * write target errors to out_dir/error.txt * add changelog entry * add changelog * format * more info for error logging * Forkserver for afl-analyze (#963) * afl-analyze forkserver * added missing vars to forkserver * synchronized a bit more with afl-tmin * more debugging, runs now, but need to suppress target output * fix dev/null setting * afl-analyze info: Co-authored-by: hexcoder- * proper newlines * reenable LLVM 3.8 ( Ubuntu 16.04 ) * FRIDA AARCH64 support (#965) Co-authored-by: Your Name * adapt docs to minimum LLVM version * adapt to minimum llvm version Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: terrynini Co-authored-by: jdhiser Co-authored-by: yuan --- GNUmakefile | 6 +- GNUmakefile.gcc_plugin | 13 +- GNUmakefile.llvm | 6 +- README.md | 6 +- docs/Changelog.md | 12 + docs/binaryonly_fuzzing.md | 3 +- docs/ideas.md | 6 + dynamic_list.txt | 62 ++-- frida_mode/README.md | 8 +- frida_mode/include/ctx.h | 11 +- frida_mode/include/instrument.h | 10 +- frida_mode/src/asan/asan_arm.c | 28 -- frida_mode/src/asan/asan_arm32.c | 28 ++ frida_mode/src/asan/asan_arm64.c | 76 ++++- frida_mode/src/cmplog/cmplog_arm.c | 19 -- frida_mode/src/cmplog/cmplog_arm32.c | 19 ++ frida_mode/src/cmplog/cmplog_arm64.c | 295 ++++++++++++++++- frida_mode/src/ctx/ctx_arm32.c | 16 + frida_mode/src/ctx/ctx_arm64.c | 303 ++++++++++++++++++ frida_mode/src/instrument/instrument.c | 5 +- frida_mode/src/instrument/instrument_arm32.c | 12 + frida_mode/src/instrument/instrument_arm64.c | 12 + frida_mode/src/instrument/instrument_debug.c | 58 ++-- frida_mode/src/instrument/instrument_x64.c | 12 + frida_mode/src/instrument/instrument_x86.c | 12 + frida_mode/src/persistent/persistent_arm64.c | 354 ++++++++++++++++++++- frida_mode/src/persistent/persistent_x64.c | 2 - frida_mode/src/persistent/persistent_x86.c | 2 - frida_mode/src/stats/stats.c | 1 - frida_mode/src/stats/stats_arm.c | 36 --- frida_mode/src/stats/stats_arm32.c | 36 +++ frida_mode/test/cmplog/GNUmakefile | 11 +- frida_mode/test/cmplog/Makefile | 4 + frida_mode/test/cmplog/cmplog.c | 2 +- frida_mode/test/fasan/GNUmakefile | 4 +- frida_mode/test/persistent_ret/GNUmakefile | 4 +- frida_mode/test/png/persistent/GNUmakefile | 14 +- frida_mode/test/png/persistent/Makefile | 3 + frida_mode/test/png/persistent/hook/GNUmakefile | 4 +- .../png/persistent/hook/aflpp_qemu_driver_hook.c | 96 ++++++ instrumentation/README.llvm.md | 2 +- instrumentation/afl-compiler-rt.o.c | 146 +++++++-- instrumentation/afl-llvm-pass.so.cc | 2 +- src/afl-analyze.c | 218 +++++-------- src/afl-cc.c | 12 +- src/afl-fuzz-init.c | 17 +- src/afl-fuzz-stats.c | 52 +-- src/afl-fuzz.c | 3 +- test/test-llvm.sh | 8 - 49 files changed, 1674 insertions(+), 397 deletions(-) delete mode 100644 frida_mode/src/asan/asan_arm.c create mode 100644 frida_mode/src/asan/asan_arm32.c delete mode 100644 frida_mode/src/cmplog/cmplog_arm.c create mode 100644 frida_mode/src/cmplog/cmplog_arm32.c create mode 100644 frida_mode/src/ctx/ctx_arm32.c create mode 100644 frida_mode/src/ctx/ctx_arm64.c delete mode 100644 frida_mode/src/stats/stats_arm.c create mode 100644 frida_mode/src/stats/stats_arm32.c (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index a45f6d5c..bd206af0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -436,8 +436,8 @@ afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-fork afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) -afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS) +afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS) afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) @@ -572,7 +572,7 @@ clean: $(MAKE) -C qemu_mode/unsigaction clean $(MAKE) -C qemu_mode/libcompcov clean $(MAKE) -C qemu_mode/libqasan clean - $(MAKE) -C frida_mode clean + -$(MAKE) -C frida_mode clean ifeq "$(IN_REPO)" "1" test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index b0f90f1b..bce97b2f 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -100,7 +100,7 @@ ifeq "$(SYS)" "SunOS" endif -PROGS = ./afl-gcc-pass.so +PROGS = ./afl-gcc-pass.so ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o .PHONY: all all: test_shm test_deps $(PROGS) test_build all_done @@ -130,6 +130,17 @@ test_deps: afl-common.o: ./src/afl-common.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ $(LDFLAGS) +./afl-compiler-rt.o: instrumentation/afl-compiler-rt.o.c + $(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@ + +./afl-compiler-rt-32.o: instrumentation/afl-compiler-rt.o.c + @printf "[*] Building 32-bit variant of the runtime (-m32)... " + @$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi + +./afl-compiler-rt-64.o: instrumentation/afl-compiler-rt.o.c + @printf "[*] Building 64-bit variant of the runtime (-m64)... " + @$(CC) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi + ./afl-gcc-pass.so: instrumentation/afl-gcc-pass.so.cc | test_deps $(CXX) $(CXXEFLAGS) $(PLUGIN_FLAGS) -shared $< -o $@ ln -sf afl-cc afl-gcc-fast diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 2d50badc..95140cb0 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -45,7 +45,7 @@ endif LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' | sed 's/svn//' ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//' ) LLVM_MINOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/.*\.//' | sed 's/git//' | sed 's/svn//' | sed 's/ .*//' ) -LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-5]\.' && echo 1 || echo 0 ) +LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^[0-2]\.|^3.[0-7]\.' && echo 1 || echo 0 ) LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[3-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 ) @@ -57,11 +57,11 @@ LLVM_APPLE_XCODE = $(shell clang -v 2>&1 | grep -q Apple && echo 1 || echo 0) LLVM_LTO = 0 ifeq "$(LLVMVER)" "" - $(warning [!] llvm_mode needs llvm-config, which was not found) + $(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.) endif ifeq "$(LLVM_UNSUPPORTED)" "1" - $(error llvm_mode only supports llvm from version 6.0 onwards) + $(error llvm_mode only supports llvm from version 3.8 onwards) endif ifeq "$(LLVM_TOO_NEW)" "1" diff --git a/README.md b/README.md index ba612edb..bc547b3c 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. @@ -296,7 +296,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 3.8+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ @@ -801,7 +801,7 @@ Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the LAF instance. Then run as many instances as you have cores left with either -Q mode or - better - -use a binary rewriter like afl-dyninst, retrowrite, zaflr, etc. +use a binary rewriter like afl-dyninst, retrowrite, zafl, etc. For Qemu and Frida mode, check out the persistent mode, it gives a huge speed improvement if it is possible to use. diff --git a/docs/Changelog.md b/docs/Changelog.md index a49c0672..6c851460 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,18 @@ sending a mail to . ### Version ++3.14a (release) - Fix for llvm 13 + - afl-fuzz: + - fix -F when a '/' was part of the parameter + - removed implied -D determinstic from -M main + - if the target becomes unavailable check out out/default/error.txt for + an indicator why + - afl-cc + - support partial linking + - We do support llvm versions from 3.8 again + - afl_analyze + - fix timeout handling and support forkserver + - ensure afl-compiler-rt is built for gcc_module + - afl-analyze now uses the forkserver for increased performance ### Version ++3.13c (release) diff --git a/docs/binaryonly_fuzzing.md b/docs/binaryonly_fuzzing.md index 11e1dbeb..3b32f5ed 100644 --- a/docs/binaryonly_fuzzing.md +++ b/docs/binaryonly_fuzzing.md @@ -122,7 +122,7 @@ [https://github.com/vanhauser-thc/afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) -## RETROWRITE +## RETROWRITE, ZAFL, ... other binary rewriter If you have an x86/x86_64 binary that still has its symbols, is compiled with position independant code (PIC/PIE) and does not use most of the C++ @@ -131,6 +131,7 @@ It is at about 80-85% performance. + [https://git.zephyr-software.com/opensrc/zafl](https://git.zephyr-software.com/opensrc/zafl) [https://github.com/HexHive/retrowrite](https://github.com/HexHive/retrowrite) diff --git a/docs/ideas.md b/docs/ideas.md index e25d3ba6..0ee69851 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -34,6 +34,12 @@ Mentor: any Other programming languages also use llvm hence they could (easily?) supported for fuzzing, e.g. mono, swift, go, kotlin native, fortran, ... +GCC also supports: Objective-C, Fortran, Ada, Go, and D +(according to [Gcc homepage](https://gcc.gnu.org/)) + +LLVM is also used by: Rust, LLGo (Go), kaleidoscope (Haskell), flang (Fortran), emscripten (JavaScript, WASM), ilwasm (CIL (C#)) +(according to [LLVM frontends](https://gist.github.com/axic/62d66fb9d8bccca6cc48fa9841db9241)) + Mentor: vanhauser-thc ## Machine Learning diff --git a/dynamic_list.txt b/dynamic_list.txt index d1905d43..7293ae77 100644 --- a/dynamic_list.txt +++ b/dynamic_list.txt @@ -1,48 +1,56 @@ { + "__afl_already_initialized_first"; + "__afl_already_initialized_forkserver"; + "__afl_already_initialized_second"; + "__afl_already_initialized_shm"; "__afl_area_ptr"; + "__afl_auto_early"; + "__afl_auto_first"; + "__afl_auto_init"; + "__afl_auto_second"; + "__afl_coverage_discard"; + "__afl_coverage_interesting"; + "__afl_coverage_off"; + "__afl_coverage_on"; + "__afl_coverage_skip"; + "__afl_dictionary"; + "__afl_dictionary_len"; + "__afl_final_loc"; + "__afl_fuzz_len"; + "__afl_fuzz_ptr"; "__afl_manual_init"; + "__afl_map_addr"; "__afl_persistent_loop"; - "__afl_auto_init"; - "__afl_area_initial"; - "__afl_prev_loc"; "__afl_prev_caller"; "__afl_prev_ctx"; - "__afl_final_loc"; - "__afl_map_addr"; - "__afl_dictionary"; - "__afl_dictionary_len"; + "__afl_prev_loc"; "__afl_selective_coverage"; "__afl_selective_coverage_start_off"; "__afl_selective_coverage_temp"; - "__afl_coverage_discard"; - "__afl_coverage_skip"; - "__afl_coverage_on"; - "__afl_coverage_off"; - "__afl_coverage_interesting"; - "__afl_fuzz_len"; - "__afl_fuzz_ptr"; "__afl_sharedmem_fuzzing"; - "__sanitizer_cov_trace_pc_guard"; - "__sanitizer_cov_trace_pc_guard_init"; + "__afl_trace"; "__cmplog_ins_hook1"; + "__cmplog_ins_hook16"; "__cmplog_ins_hook2"; "__cmplog_ins_hook4"; + "__cmplog_ins_hook8"; "__cmplog_ins_hookN"; - "__cmplog_ins_hook16"; + "__cmplog_rtn_gcc_stdstring_cstring"; + "__cmplog_rtn_gcc_stdstring_stdstring"; + "__cmplog_rtn_hook"; + "__cmplog_rtn_llvm_stdstring_cstring"; + "__cmplog_rtn_llvm_stdstring_stdstring"; "__sanitizer_cov_trace_cmp1"; - "__sanitizer_cov_trace_const_cmp1"; + "__sanitizer_cov_trace_cmp16"; "__sanitizer_cov_trace_cmp2"; - "__sanitizer_cov_trace_const_cmp2"; "__sanitizer_cov_trace_cmp4"; - "__sanitizer_cov_trace_const_cmp4"; "__sanitizer_cov_trace_cmp8"; - "__sanitizer_cov_trace_const_cmp8"; - "__sanitizer_cov_trace_cmp16"; + "__sanitizer_cov_trace_const_cmp1"; "__sanitizer_cov_trace_const_cmp16"; + "__sanitizer_cov_trace_const_cmp2"; + "__sanitizer_cov_trace_const_cmp4"; + "__sanitizer_cov_trace_const_cmp8"; + "__sanitizer_cov_trace_pc_guard"; + "__sanitizer_cov_trace_pc_guard_init"; "__sanitizer_cov_trace_switch"; - "__cmplog_rtn_hook"; - "__cmplog_rtn_gcc_stdstring_cstring"; - "__cmplog_rtn_gcc_stdstring_stdstring"; - "__cmplog_rtn_llvm_stdstring_cstring"; - "__cmplog_rtn_llvm_stdstring_stdstring"; }; diff --git a/frida_mode/README.md b/frida_mode/README.md index 0103a395..d7dd72a0 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -21,16 +21,16 @@ perhaps leverage some of its design and implementation. | Feature/Instrumentation | frida-mode | Notes | | -------------------------|:----------:|:--------------------------------------------:| | NeverZero | x | | - | Persistent Mode | x | (x86/x64 only)(Only on function boundaries) | + | Persistent Mode | x | (x86/x64/aarch64 only) | | LAF-Intel / CompCov | - | (CMPLOG is better 90% of the time) | - | CMPLOG | x | (x86/x64 only) | + | CMPLOG | x | (x86/x64/aarch64 only) | | Selective Instrumentation| x | | | Non-Colliding Coverage | - | (Not possible in binary-only instrumentation | | Ngram prev_loc Coverage | - | | | Context Coverage | - | | | Auto Dictionary | - | | | Snapshot LKM Support | - | | - | In-Memory Test Cases | x | (x86/x64 only) | + | In-Memory Test Cases | x | (x86/x64/aarch64 only) | ## Compatibility Currently FRIDA mode supports Linux and macOS targets on both x86/x64 @@ -288,7 +288,7 @@ to validate memory accesses against the shadow memory. ## TODO -The next features to be added are Aarch64 and Aarch32 support as well as looking at +The next features to be added are Aarch32 support as well as looking at potential performance improvements. The intention is to achieve feature parity with QEMU mode in due course. Contributions are welcome, but please get in touch to ensure that efforts are deconflicted. diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h index cbcc892a..67274aee 100644 --- a/frida_mode/include/ctx.h +++ b/frida_mode/include/ctx.h @@ -3,8 +3,15 @@ #include "frida-gum.h" -#if defined(__x86_64__) || defined(__i386__) -gsize ctx_read_reg(GumCpuContext *ctx, x86_reg reg); +#if defined(__x86_64__) +gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg); +#elif defined(__i386__) +gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg); +#elif defined(__aarch64__) +gsize ctx_read_reg(GumArm64CpuContext *ctx, arm64_reg reg); +size_t ctx_get_size(const cs_insn *instr, cs_arm64_op *operand); +#elif defined(__arm__) +gsize ctx_read_reg(GumArmCpuContext *ctx, arm_reg reg); #endif #endif diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index ed92c25a..577481d1 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -19,9 +19,11 @@ gboolean instrument_is_coverage_optimize_supported(void); void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output); -void instrument_debug_init(void); -void instrument_debug_start(uint64_t address, GumStalkerOutput *output); -void instrument_debug_instruction(uint64_t address, uint16_t size); -void instrument_debug_end(GumStalkerOutput *output); +void instrument_debug_init(void); +void instrument_debug_start(uint64_t address, GumStalkerOutput *output); +void instrument_debug_instruction(uint64_t address, uint16_t size); +void instrument_debug_end(GumStalkerOutput *output); +void instrument_flush(GumStalkerOutput *output); +gpointer instrument_cur(GumStalkerOutput *output); #endif diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c deleted file mode 100644 index 79475ced..00000000 --- a/frida_mode/src/asan/asan_arm.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "frida-gum.h" - -#include "debug.h" - -#include "asan.h" -#include "util.h" - -#if defined(__arm__) -void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { - - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(iterator); - if (asan_initialized) { - - FATAL("ASAN mode not supported on this architecture"); - - } - -} - -void asan_arch_init(void) { - - FATAL("ASAN mode not supported on this architecture"); - -} - -#endif - diff --git a/frida_mode/src/asan/asan_arm32.c b/frida_mode/src/asan/asan_arm32.c new file mode 100644 index 00000000..79475ced --- /dev/null +++ b/frida_mode/src/asan/asan_arm32.c @@ -0,0 +1,28 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__arm__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +void asan_arch_init(void) { + + FATAL("ASAN mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c index 6262ee18..66138e42 100644 --- a/frida_mode/src/asan/asan_arm64.c +++ b/frida_mode/src/asan/asan_arm64.c @@ -1,18 +1,80 @@ +#include #include "frida-gum.h" #include "debug.h" #include "asan.h" +#include "ctx.h" #include "util.h" #if defined(__aarch64__) + +typedef struct { + + size_t size; + cs_arm64_op operand; + +} asan_ctx_t; + +typedef void (*asan_loadN_t)(gsize address, uint8_t size); +typedef void (*asan_storeN_t)(gsize address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + asan_ctx_t * asan_ctx = (asan_ctx_t *)user_data; + cs_arm64_op * operand = &asan_ctx->operand; + arm64_op_mem *mem = &operand->mem; + gsize base = 0; + gsize index = 0; + gsize address; + + if (mem->base != ARM64_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != ARM64_REG_INVALID) { + + index = ctx_read_reg(ctx, mem->index); + + } + + address = base + index + mem->disp; + + if ((operand->access & CS_AC_READ) == CS_AC_READ) { + + asan_loadN(address, asan_ctx->size); + + } + + if ((operand->access & CS_AC_WRITE) == CS_AC_WRITE) { + + asan_storeN(address, asan_ctx->size); + + } + +} + void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { - UNUSED_PARAMETER(instr); UNUSED_PARAMETER(iterator); - if (asan_initialized) { - FATAL("ASAN mode not supported on this architecture"); + cs_arm64 arm64 = instr->detail->arm64; + cs_arm64_op *operand; + asan_ctx_t * ctx; + + if (!asan_initialized) return; + + for (uint8_t i = 0; i < arm64.op_count; i++) { + + operand = &arm64.operands[i]; + + if (operand->type != ARM64_OP_MEM) { continue; } + + ctx = g_malloc0(sizeof(asan_ctx_t)); + ctx->size = ctx_get_size(instr, &arm64.operands[0]); + memcpy(&ctx->operand, operand, sizeof(cs_arm64_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); } @@ -20,7 +82,13 @@ void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { void asan_arch_init(void) { - FATAL("ASAN mode not supported on this architecture"); + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } } diff --git a/frida_mode/src/cmplog/cmplog_arm.c b/frida_mode/src/cmplog/cmplog_arm.c deleted file mode 100644 index 5af28f3f..00000000 --- a/frida_mode/src/cmplog/cmplog_arm.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "frida-gum.h" - -#include "debug.h" - -#include "frida_cmplog.h" -#include "util.h" - -#if defined(__arm__) -void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { - - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(iterator); - if (__afl_cmp_map == NULL) { return; } - FATAL("CMPLOG mode not supported on this architecture"); - -} - -#endif - diff --git a/frida_mode/src/cmplog/cmplog_arm32.c b/frida_mode/src/cmplog/cmplog_arm32.c new file mode 100644 index 00000000..5af28f3f --- /dev/null +++ b/frida_mode/src/cmplog/cmplog_arm32.c @@ -0,0 +1,19 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "frida_cmplog.h" +#include "util.h" + +#if defined(__arm__) +void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (__afl_cmp_map == NULL) { return; } + FATAL("CMPLOG mode not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_arm64.c b/frida_mode/src/cmplog/cmplog_arm64.c index 187d0162..04631ff8 100644 --- a/frida_mode/src/cmplog/cmplog_arm64.c +++ b/frida_mode/src/cmplog/cmplog_arm64.c @@ -1,17 +1,304 @@ #include "frida-gum.h" #include "debug.h" +#include "cmplog.h" +#include "ctx.h" #include "frida_cmplog.h" #include "util.h" #if defined(__aarch64__) + +typedef struct { + + arm64_op_type type; + uint8_t size; + + union { + + arm64_op_mem mem; + arm64_reg reg; + int64_t imm; + + }; + +} cmplog_ctx_t; + +typedef struct { + + cmplog_ctx_t operand1; + cmplog_ctx_t operand2; + size_t size; + +} cmplog_pair_ctx_t; + +static gboolean cmplog_read_mem(GumCpuContext *ctx, uint8_t size, + arm64_op_mem *mem, gsize *val) { + + gsize base = 0; + gsize index = 0; + gsize address; + + if (mem->base != ARM64_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != ARM64_REG_INVALID) { + + index = ctx_read_reg(ctx, mem->index); + + } + + address = base + index + mem->disp; + + if (!cmplog_is_readable(address, size)) { return FALSE; } + + switch (size) { + + case 1: + *val = *((guint8 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 2: + *val = *((guint16 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 4: + *val = *((guint32 *)GSIZE_TO_POINTER(address)); + return TRUE; + case 8: + *val = *((guint64 *)GSIZE_TO_POINTER(address)); + return TRUE; + default: + FATAL("Invalid operand size: %d\n", size); + + } + + return FALSE; + +} + +static gboolean cmplog_get_operand_value(GumCpuContext *context, + cmplog_ctx_t *ctx, gsize *val) { + + switch (ctx->type) { + + case ARM64_OP_REG: + *val = ctx_read_reg(context, ctx->reg); + return TRUE; + case ARM64_OP_IMM: + *val = ctx->imm; + return TRUE; + case ARM64_OP_MEM: + return cmplog_read_mem(context, ctx->size, &ctx->mem, val); + default: + FATAL("Invalid operand type: %d\n", ctx->type); + + } + + return FALSE; + +} + +static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + gsize address = context->pc; + gsize x0 = ctx_read_reg(context, ARM64_REG_X0); + gsize x1 = ctx_read_reg(context, ARM64_REG_X1); + + if (((G_MAXULONG - x0) < 32) || ((G_MAXULONG - x1) < 32)) return; + + if (!cmplog_is_readable(x0, 32) || !cmplog_is_readable(x1, 32)) return; + + void *ptr1 = GSIZE_TO_POINTER(x0); + void *ptr2 = GSIZE_TO_POINTER(x1); + + uintptr_t k = address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 31; + + hits &= CMP_MAP_RTN_H - 1; + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, ptr1, + 32); + gum_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, ptr2, + 32); + +} + +static void cmplog_instrument_put_operand(cmplog_ctx_t *ctx, + cs_arm64_op * operand) { + + ctx->type = operand->type; + switch (operand->type) { + + case ARM64_OP_REG: + gum_memcpy(&ctx->reg, &operand->reg, sizeof(arm64_reg)); + break; + case ARM64_OP_IMM: + gum_memcpy(&ctx->imm, &operand->imm, sizeof(int64_t)); + break; + case ARM64_OP_MEM: + gum_memcpy(&ctx->mem, &operand->mem, sizeof(arm64_op_mem)); + break; + default: + FATAL("Invalid operand type: %d\n", operand->type); + + } + +} + +static void cmplog_instrument_call(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_arm64 arm64 = instr->detail->arm64; + cs_arm64_op *operand; + + switch (instr->id) { + + case ARM64_INS_BL: + case ARM64_INS_BLR: + case ARM64_INS_BLRAA: + case ARM64_INS_BLRAAZ: + case ARM64_INS_BLRAB: + case ARM64_INS_BLRABZ: + break; + default: + return; + + } + + if (arm64.op_count != 1) return; + + operand = &arm64.operands[0]; + + if (operand->type == ARM64_OP_INVALID) return; + + gum_stalker_iterator_put_callout(iterator, cmplog_call_callout, NULL, NULL); + +} + +static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, + gsize operand2, uint8_t size) { + + gsize address = context->pc; + + register uintptr_t k = (uintptr_t)address; + + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = (size - 1); + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = operand1; + __afl_cmp_map->log[k][hits].v1 = operand2; + +} + +static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { + + cmplog_pair_ctx_t *ctx = (cmplog_pair_ctx_t *)user_data; + gsize operand1; + gsize operand2; + + if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } + if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } + + cmplog_handle_cmp_sub(context, operand1, operand2, ctx->size); + +} + +static void cmplog_instrument_cmp_sub_put_callout(GumStalkerIterator *iterator, + cs_arm64_op * operand1, + cs_arm64_op * operand2, + size_t size) { + + cmplog_pair_ctx_t *ctx = g_malloc(sizeof(cmplog_pair_ctx_t)); + if (ctx == NULL) return; + + cmplog_instrument_put_operand(&ctx->operand1, operand1); + cmplog_instrument_put_operand(&ctx->operand2, operand2); + ctx->size = size; + + gum_stalker_iterator_put_callout(iterator, cmplog_cmp_sub_callout, ctx, + g_free); + +} + +static void cmplog_instrument_cmp_sub(const cs_insn * instr, + GumStalkerIterator *iterator) { + + cs_arm64 arm64 = instr->detail->arm64; + cs_arm64_op *operand1; + cs_arm64_op *operand2; + size_t size; + + switch (instr->id) { + + case ARM64_INS_ADCS: + case ARM64_INS_ADDS: + case ARM64_INS_ANDS: + case ARM64_INS_BICS: + case ARM64_INS_CMN: + case ARM64_INS_CMP: + case ARM64_INS_CMPEQ: + case ARM64_INS_CMPGE: + case ARM64_INS_CMPGT: + case ARM64_INS_CMPHI: + case ARM64_INS_CMPHS: + case ARM64_INS_CMPLE: + case ARM64_INS_CMPLO: + case ARM64_INS_CMPLS: + case ARM64_INS_CMPLT: + case ARM64_INS_CMPNE: + case ARM64_INS_EORS: + case ARM64_INS_NANDS: + case ARM64_INS_NEGS: + case ARM64_INS_NGCS: + case ARM64_INS_NORS: + case ARM64_INS_NOTS: + case ARM64_INS_ORNS: + case ARM64_INS_ORRS: + case ARM64_INS_SBCS: + case ARM64_INS_SUBS: + break; + + default: + return; + + } + + if (arm64.op_count != 2) return; + + operand1 = &arm64.operands[0]; + operand2 = &arm64.operands[1]; + + if (operand1->type == ARM64_OP_INVALID) return; + if (operand2->type == ARM64_OP_INVALID) return; + + size = ctx_get_size(instr, &arm64.operands[0]); + + cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2, size); + +} + void cmplog_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(iterator); - if (__afl_cmp_map == NULL) { return; } - FATAL("CMPLOG mode not supported on this architecture"); + if (__afl_cmp_map == NULL) return; + + cmplog_instrument_call(instr, iterator); + cmplog_instrument_cmp_sub(instr, iterator); } diff --git a/frida_mode/src/ctx/ctx_arm32.c b/frida_mode/src/ctx/ctx_arm32.c new file mode 100644 index 00000000..a5c6f6d4 --- /dev/null +++ b/frida_mode/src/ctx/ctx_arm32.c @@ -0,0 +1,16 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__arm__) + +gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) { + + FATAL("ctx_read_reg unimplemented for this architecture"); + +} + +#endif + diff --git a/frida_mode/src/ctx/ctx_arm64.c b/frida_mode/src/ctx/ctx_arm64.c new file mode 100644 index 00000000..d09896af --- /dev/null +++ b/frida_mode/src/ctx/ctx_arm64.c @@ -0,0 +1,303 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__aarch64__) + + #define ARM64_REG_8(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define ARM64_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define ARM64_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define ARM64_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +gsize ctx_read_reg(GumArm64CpuContext *ctx, arm64_reg reg) { + + switch (reg) { + + case ARM64_REG_WZR: + case ARM64_REG_XZR: + return 0; + + ARM64_REG_8(ARM64_REG_B0, ctx->x[0]) + ARM64_REG_8(ARM64_REG_B1, ctx->x[1]) + ARM64_REG_8(ARM64_REG_B2, ctx->x[2]) + ARM64_REG_8(ARM64_REG_B3, ctx->x[3]) + ARM64_REG_8(ARM64_REG_B4, ctx->x[4]) + ARM64_REG_8(ARM64_REG_B5, ctx->x[5]) + ARM64_REG_8(ARM64_REG_B6, ctx->x[6]) + ARM64_REG_8(ARM64_REG_B7, ctx->x[7]) + ARM64_REG_8(ARM64_REG_B8, ctx->x[8]) + ARM64_REG_8(ARM64_REG_B9, ctx->x[9]) + ARM64_REG_8(ARM64_REG_B10, ctx->x[10]) + ARM64_REG_8(ARM64_REG_B11, ctx->x[11]) + ARM64_REG_8(ARM64_REG_B12, ctx->x[12]) + ARM64_REG_8(ARM64_REG_B13, ctx->x[13]) + ARM64_REG_8(ARM64_REG_B14, ctx->x[14]) + ARM64_REG_8(ARM64_REG_B15, ctx->x[15]) + ARM64_REG_8(ARM64_REG_B16, ctx->x[16]) + ARM64_REG_8(ARM64_REG_B17, ctx->x[17]) + ARM64_REG_8(ARM64_REG_B18, ctx->x[18]) + ARM64_REG_8(ARM64_REG_B19, ctx->x[19]) + ARM64_REG_8(ARM64_REG_B20, ctx->x[20]) + ARM64_REG_8(ARM64_REG_B21, ctx->x[21]) + ARM64_REG_8(ARM64_REG_B22, ctx->x[22]) + ARM64_REG_8(ARM64_REG_B23, ctx->x[23]) + ARM64_REG_8(ARM64_REG_B24, ctx->x[24]) + ARM64_REG_8(ARM64_REG_B25, ctx->x[25]) + ARM64_REG_8(ARM64_REG_B26, ctx->x[26]) + ARM64_REG_8(ARM64_REG_B27, ctx->x[27]) + ARM64_REG_8(ARM64_REG_B28, ctx->x[28]) + ARM64_REG_8(ARM64_REG_B29, ctx->fp) + ARM64_REG_8(ARM64_REG_B30, ctx->lr) + ARM64_REG_8(ARM64_REG_B31, ctx->sp) + + ARM64_REG_16(ARM64_REG_H0, ctx->x[0]) + ARM64_REG_16(ARM64_REG_H1, ctx->x[1]) + ARM64_REG_16(ARM64_REG_H2, ctx->x[2]) + ARM64_REG_16(ARM64_REG_H3, ctx->x[3]) + ARM64_REG_16(ARM64_REG_H4, ctx->x[4]) + ARM64_REG_16(ARM64_REG_H5, ctx->x[5]) + ARM64_REG_16(ARM64_REG_H6, ctx->x[6]) + ARM64_REG_16(ARM64_REG_H7, ctx->x[7]) + ARM64_REG_16(ARM64_REG_H8, ctx->x[8]) + ARM64_REG_16(ARM64_REG_H9, ctx->x[9]) + ARM64_REG_16(ARM64_REG_H10, ctx->x[10]) + ARM64_REG_16(ARM64_REG_H11, ctx->x[11]) + ARM64_REG_16(ARM64_REG_H12, ctx->x[12]) + ARM64_REG_16(ARM64_REG_H13, ctx->x[13]) + ARM64_REG_16(ARM64_REG_H14, ctx->x[14]) + ARM64_REG_16(ARM64_REG_H15, ctx->x[15]) + ARM64_REG_16(ARM64_REG_H16, ctx->x[16]) + ARM64_REG_16(ARM64_REG_H17, ctx->x[17]) + ARM64_REG_16(ARM64_REG_H18, ctx->x[18]) + ARM64_REG_16(ARM64_REG_H19, ctx->x[19]) + ARM64_REG_16(ARM64_REG_H20, ctx->x[20]) + ARM64_REG_16(ARM64_REG_H21, ctx->x[21]) + ARM64_REG_16(ARM64_REG_H22, ctx->x[22]) + ARM64_REG_16(ARM64_REG_H23, ctx->x[23]) + ARM64_REG_16(ARM64_REG_H24, ctx->x[24]) + ARM64_REG_16(ARM64_REG_H25, ctx->x[25]) + ARM64_REG_16(ARM64_REG_H26, ctx->x[26]) + ARM64_REG_16(ARM64_REG_H27, ctx->x[27]) + ARM64_REG_16(ARM64_REG_H28, ctx->x[28]) + ARM64_REG_16(ARM64_REG_H29, ctx->fp) + ARM64_REG_16(ARM64_REG_H30, ctx->lr) + ARM64_REG_16(ARM64_REG_H31, ctx->sp) + + ARM64_REG_32(ARM64_REG_W0, ctx->x[0]) + ARM64_REG_32(ARM64_REG_W1, ctx->x[1]) + ARM64_REG_32(ARM64_REG_W2, ctx->x[2]) + ARM64_REG_32(ARM64_REG_W3, ctx->x[3]) + ARM64_REG_32(ARM64_REG_W4, ctx->x[4]) + ARM64_REG_32(ARM64_REG_W5, ctx->x[5]) + ARM64_REG_32(ARM64_REG_W6, ctx->x[6]) + ARM64_REG_32(ARM64_REG_W7, ctx->x[7]) + ARM64_REG_32(ARM64_REG_W8, ctx->x[8]) + ARM64_REG_32(ARM64_REG_W9, ctx->x[9]) + ARM64_REG_32(ARM64_REG_W10, ctx->x[10]) + ARM64_REG_32(ARM64_REG_W11, ctx->x[11]) + ARM64_REG_32(ARM64_REG_W12, ctx->x[12]) + ARM64_REG_32(ARM64_REG_W13, ctx->x[13]) + ARM64_REG_32(ARM64_REG_W14, ctx->x[14]) + ARM64_REG_32(ARM64_REG_W15, ctx->x[15]) + ARM64_REG_32(ARM64_REG_W16, ctx->x[16]) + ARM64_REG_32(ARM64_REG_W17, ctx->x[17]) + ARM64_REG_32(ARM64_REG_W18, ctx->x[18]) + ARM64_REG_32(ARM64_REG_W19, ctx->x[19]) + ARM64_REG_32(ARM64_REG_W20, ctx->x[20]) + ARM64_REG_32(ARM64_REG_W21, ctx->x[21]) + ARM64_REG_32(ARM64_REG_W22, ctx->x[22]) + ARM64_REG_32(ARM64_REG_W23, ctx->x[23]) + ARM64_REG_32(ARM64_REG_W24, ctx->x[24]) + ARM64_REG_32(ARM64_REG_W25, ctx->x[25]) + ARM64_REG_32(ARM64_REG_W26, ctx->x[26]) + ARM64_REG_32(ARM64_REG_W27, ctx->x[27]) + ARM64_REG_32(ARM64_REG_W28, ctx->x[28]) + ARM64_REG_32(ARM64_REG_W29, ctx->fp) + ARM64_REG_32(ARM64_REG_W30, ctx->lr) + + ARM64_REG_64(ARM64_REG_X0, ctx->x[0]) + ARM64_REG_64(ARM64_REG_X1, ctx->x[1]) + ARM64_REG_64(ARM64_REG_X2, ctx->x[2]) + ARM64_REG_64(ARM64_REG_X3, ctx->x[3]) + ARM64_REG_64(ARM64_REG_X4, ctx->x[4]) + ARM64_REG_64(ARM64_REG_X5, ctx->x[5]) + ARM64_REG_64(ARM64_REG_X6, ctx->x[6]) + ARM64_REG_64(ARM64_REG_X7, ctx->x[7]) + ARM64_REG_64(ARM64_REG_X8, ctx->x[8]) + ARM64_REG_64(ARM64_REG_X9, ctx->x[9]) + ARM64_REG_64(ARM64_REG_X10, ctx->x[10]) + ARM64_REG_64(ARM64_REG_X11, ctx->x[11]) + ARM64_REG_64(ARM64_REG_X12, ctx->x[12]) + ARM64_REG_64(ARM64_REG_X13, ctx->x[13]) + ARM64_REG_64(ARM64_REG_X14, ctx->x[14]) + ARM64_REG_64(ARM64_REG_X15, ctx->x[15]) + ARM64_REG_64(ARM64_REG_X16, ctx->x[16]) + ARM64_REG_64(ARM64_REG_X17, ctx->x[17]) + ARM64_REG_64(ARM64_REG_X18, ctx->x[18]) + ARM64_REG_64(ARM64_REG_X19, ctx->x[19]) + ARM64_REG_64(ARM64_REG_X20, ctx->x[20]) + ARM64_REG_64(ARM64_REG_X21, ctx->x[21]) + ARM64_REG_64(ARM64_REG_X22, ctx->x[22]) + ARM64_REG_64(ARM64_REG_X23, ctx->x[23]) + ARM64_REG_64(ARM64_REG_X24, ctx->x[24]) + ARM64_REG_64(ARM64_REG_X25, ctx->x[25]) + ARM64_REG_64(ARM64_REG_X26, ctx->x[26]) + ARM64_REG_64(ARM64_REG_X27, ctx->x[27]) + ARM64_REG_64(ARM64_REG_X28, ctx->x[28]) + ARM64_REG_64(ARM64_REG_FP, ctx->fp) + ARM64_REG_64(ARM64_REG_LR, ctx->lr) + ARM64_REG_64(ARM64_REG_SP, ctx->sp) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +size_t ctx_get_size(const cs_insn *instr, cs_arm64_op *operand) { + + uint8_t num_registers; + uint8_t count_byte; + char vas_digit; + size_t mnemonic_len; + + switch (instr->id) { + + case ARM64_INS_STP: + case ARM64_INS_STXP: + case ARM64_INS_STNP: + case ARM64_INS_STLXP: + case ARM64_INS_LDP: + case ARM64_INS_LDXP: + case ARM64_INS_LDNP: + num_registers = 2; + break; + default: + num_registers = 1; + break; + + } + + mnemonic_len = strlen(instr->mnemonic); + if (mnemonic_len == 0) { FATAL("No mnemonic found"); }; + + char last = instr->mnemonic[mnemonic_len - 1]; + switch (last) { + + case 'b': + return 1; + case 'h': + return 2; + case 'w': + return 4 * num_registers; + + } + + if (operand->vas == ARM64_VAS_INVALID) { + + if (operand->type == ARM64_OP_REG) { + + switch (operand->reg) { + + case ARM64_REG_WZR: + case ARM64_REG_WSP: + case ARM64_REG_W0 ... ARM64_REG_W30: + case ARM64_REG_S0 ... ARM64_REG_S31: + return 4 * num_registers; + case ARM64_REG_D0 ... ARM64_REG_D31: + return 8 * num_registers; + case ARM64_REG_Q0 ... ARM64_REG_Q31: + return 16; + default: + return 8 * num_registers; + ; + + } + + } + + return 8 * num_registers; + + } + + if (g_str_has_prefix(instr->mnemonic, "st") || + g_str_has_prefix(instr->mnemonic, "ld")) { + + if (mnemonic_len < 3) { + + FATAL("VAS Mnemonic too short: %s\n", instr->mnemonic); + + } + + vas_digit = instr->mnemonic[2]; + if (vas_digit < '0' || vas_digit > '9') { + + FATAL("VAS Mnemonic digit out of range: %s\n", instr->mnemonic); + + } + + count_byte = vas_digit - '0'; + + } else { + + count_byte = 1; + + } + + switch (operand->vas) { + + case ARM64_VAS_1B: + return 1 * count_byte; + case ARM64_VAS_1H: + return 2 * count_byte; + case ARM64_VAS_4B: + case ARM64_VAS_1S: + case ARM64_VAS_1D: + case ARM64_VAS_2H: + return 4 * count_byte; + case ARM64_VAS_8B: + case ARM64_VAS_4H: + case ARM64_VAS_2S: + case ARM64_VAS_2D: + case ARM64_VAS_1Q: + return 8 * count_byte; + case ARM64_VAS_8H: + case ARM64_VAS_4S: + case ARM64_VAS_16B: + return 16 * count_byte; + default: + FATAL("Unexpected VAS type: %s %d", instr->mnemonic, operand->vas); + + } + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index cd1ac0be..f261e79a 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -84,6 +84,8 @@ static void instr_basic_block(GumStalkerIterator *iterator, while (gum_stalker_iterator_next(iterator, &instr)) { + if (unlikely(begin)) { instrument_debug_start(instr->address, output); } + if (instr->address == entry_start) { entry_prologue(iterator, output); } if (instr->address == persistent_start) { persistent_prologue(output); } if (instr->address == persistent_ret) { persistent_epilogue(output); } @@ -119,8 +121,6 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (unlikely(begin)) { - instrument_debug_start(instr->address, output); - prefetch_write(GSIZE_TO_POINTER(instr->address)); if (likely(!excluded)) { @@ -155,6 +155,7 @@ static void instr_basic_block(GumStalkerIterator *iterator, } + instrument_flush(output); instrument_debug_end(output); } diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 1a3c40bb..450a69a3 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -22,5 +22,17 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_flush(GumStalkerOutput *output) { + + gum_arm_writer_flush(output->writer.arm); + +} + +gpointer instrument_cur(GumStalkerOutput *output) { + + return gum_arm_writer_cur(output->writer.arm); + +} + #endif diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index fa3afb48..49ee86a2 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -93,5 +93,17 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_flush(GumStalkerOutput *output) { + + gum_arm64_writer_flush(output->writer.arm64); + +} + +gpointer instrument_cur(GumStalkerOutput *output) { + + return gum_arm64_writer_cur(output->writer.arm64); + +} + #endif diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index f8c1df77..0ce26a1c 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -7,6 +7,7 @@ #include "debug.h" +#include "instrument.h" #include "util.h" static int debugging_fd = -1; @@ -31,44 +32,50 @@ static void instrument_debug(char *format, ...) { } -static void instrument_disasm(guint8 *code, guint size) { +static void instrument_disasm(guint8 *start, guint8 *end) { csh capstone; cs_err err; + uint16_t size; cs_insn *insn; - size_t count, i; + size_t count = 0; + size_t i; + uint16_t len; err = cs_open(GUM_DEFAULT_CS_ARCH, GUM_DEFAULT_CS_MODE | GUM_DEFAULT_CS_ENDIAN, &capstone); g_assert(err == CS_ERR_OK); - count = cs_disasm(capstone, code, size, GPOINTER_TO_SIZE(code), 0, &insn); - g_assert(insn != NULL); + size = GPOINTER_TO_SIZE(end) - GPOINTER_TO_SIZE(start); - for (i = 0; i != count; i++) { + for (guint8 *curr = start; curr < end; curr += len, size -= len, len = 0) { - instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t%s %s\n", insn[i].address, - insn[i].mnemonic, insn[i].op_str); + count = cs_disasm(capstone, curr, size, GPOINTER_TO_SIZE(curr), 0, &insn); + if (insn == NULL) { - } + instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t* 0x%016" G_GSIZE_MODIFIER + "x\n", + curr, *(size_t *)curr); - cs_free(insn, count); + len += sizeof(size_t); + continue; - cs_close(&capstone); + } -} + for (i = 0; i != count; i++) { + + instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t%s %s\n", insn[i].address, + insn[i].mnemonic, insn[i].op_str); + + len += insn[i].size; -static gpointer instrument_cur(GumStalkerOutput *output) { + } -#if defined(__i386__) || defined(__x86_64__) - return gum_x86_writer_cur(output->writer.x86); -#elif defined(__aarch64__) - return gum_arm64_writer_cur(output->writer.arm64); -#elif defined(__arm__) - return gum_arm_writer_cur(output->writer.arm); -#else - #error "Unsupported architecture" -#endif + } + + cs_free(insn, count); + + cs_close(&capstone); } @@ -111,7 +118,7 @@ void instrument_debug_instruction(uint64_t address, uint16_t size) { if (likely(debugging_fd < 0)) { return; } uint8_t *start = (uint8_t *)GSIZE_TO_POINTER(address); - instrument_disasm(start, size); + instrument_disasm(start, start + size); } @@ -119,11 +126,10 @@ void instrument_debug_end(GumStalkerOutput *output) { if (likely(debugging_fd < 0)) { return; } gpointer instrument_gen_end = instrument_cur(output); - uint16_t size = GPOINTER_TO_SIZE(instrument_gen_end) - - GPOINTER_TO_SIZE(instrument_gen_start); - instrument_debug("\nGenerated block %p\n", instrument_gen_start); - instrument_disasm(instrument_gen_start, size); + instrument_debug("\nGenerated block %p-%p\n", instrument_gen_start, + instrument_gen_end); + instrument_disasm(instrument_gen_start, instrument_gen_end); } diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index 901f3bd0..7000e65d 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -89,5 +89,17 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_flush(GumStalkerOutput *output) { + + gum_x86_writer_flush(output->writer.x86); + +} + +gpointer instrument_cur(GumStalkerOutput *output) { + + return gum_x86_writer_cur(output->writer.x86); + +} + #endif diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 585bb5b8..04a19e08 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -81,5 +81,17 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_flush(GumStalkerOutput *output) { + + gum_x86_writer_flush(output->writer.x86); + +} + +gpointer instrument_cur(GumStalkerOutput *output) { + + return gum_x86_writer_cur(output->writer.x86); + +} + #endif diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c index 1215d8da..b23693fe 100644 --- a/frida_mode/src/persistent/persistent_arm64.c +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -1,9 +1,11 @@ +#include #include "frida-gum.h" #include "config.h" #include "debug.h" #include "instrument.h" +#include "persistent.h" #include "util.h" #if defined(__aarch64__) @@ -98,23 +100,365 @@ struct arm64_regs { typedef struct arm64_regs arch_api_regs; +static arch_api_regs saved_regs = {0}; +static gpointer saved_lr = NULL; + gboolean persistent_is_supported(void) { - return false; + return true; + +} + +static void instrument_persitent_save_regs(GumArm64Writer * cw, + struct arm64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + const guint32 mrs_x1_nzcv = 0xd53b4201; + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, + ARM64_REG_SP, -(16), + GUM_INDEX_PRE_ADJUST); + + gum_arm64_writer_put_instruction(cw, mrs_x1_nzcv); + + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, + GUM_ADDRESS(regs_address)); + + /* Skip x0 & x1 we'll do that later */ + + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, + ARM64_REG_X0, (16 * 1), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5, + ARM64_REG_X0, (16 * 2), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7, + ARM64_REG_X0, (16 * 3), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9, + ARM64_REG_X0, (16 * 4), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11, + ARM64_REG_X0, (16 * 5), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13, + ARM64_REG_X0, (16 * 6), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15, + ARM64_REG_X0, (16 * 7), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17, + ARM64_REG_X0, (16 * 8), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19, + ARM64_REG_X0, (16 * 9), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21, + ARM64_REG_X0, (16 * 10), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23, + ARM64_REG_X0, (16 * 11), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25, + ARM64_REG_X0, (16 * 12), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27, + ARM64_REG_X0, (16 * 13), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29, + ARM64_REG_X0, (16 * 14), + GUM_INDEX_SIGNED_OFFSET); + + /* LR & Adjusted SP */ + gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_SP, + (GUM_RED_ZONE_SIZE + 32)); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X2, + ARM64_REG_X0, (16 * 15), + GUM_INDEX_SIGNED_OFFSET); + + /* PC & CPSR */ + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2, + GUM_ADDRESS(persistent_start)); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1, + ARM64_REG_X0, (16 * 16), + GUM_INDEX_SIGNED_OFFSET); + + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1, + ARM64_REG_X0, (16 * 17), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3, + ARM64_REG_X0, (16 * 18), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5, + ARM64_REG_X0, (16 * 19), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7, + ARM64_REG_X0, (16 * 20), + GUM_INDEX_SIGNED_OFFSET); + + /* x0 & x1 */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, + ARM64_REG_SP, 16, + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, + ARM64_REG_X0, (16 * 0), + GUM_INDEX_SIGNED_OFFSET); + + /* Pop the saved values */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_SP, 16, GUM_INDEX_POST_ADJUST); + + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); + +} + +static void instrument_persitent_restore_regs(GumArm64Writer * cw, + struct arm64_regs *regs) { + + GumAddress regs_address = GUM_ADDRESS(regs); + const guint32 msr_nzcv_x1 = 0xd51b4201; + + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, + GUM_ADDRESS(regs_address)); + + /* Skip x0 - x3 we'll do that last */ + + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5, + ARM64_REG_X0, (16 * 2), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7, + ARM64_REG_X0, (16 * 3), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9, + ARM64_REG_X0, (16 * 4), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11, + ARM64_REG_X0, (16 * 5), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13, + ARM64_REG_X0, (16 * 6), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15, + ARM64_REG_X0, (16 * 7), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17, + ARM64_REG_X0, (16 * 8), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19, + ARM64_REG_X0, (16 * 9), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21, + ARM64_REG_X0, (16 * 10), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23, + ARM64_REG_X0, (16 * 11), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25, + ARM64_REG_X0, (16 * 12), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27, + ARM64_REG_X0, (16 * 13), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29, + ARM64_REG_X0, (16 * 14), + GUM_INDEX_SIGNED_OFFSET); + + /* Don't restore RIP or RSP, use x1-x3 as clobber */ + + /* LR & Adjusted SP (clobber x1) */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X1, + ARM64_REG_X0, (16 * 15), + GUM_INDEX_SIGNED_OFFSET); + + /* PC (x2) & CPSR (x1) */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1, + ARM64_REG_X0, (16 * 16), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_instruction(cw, msr_nzcv_x1); + + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1, + ARM64_REG_X0, (16 * 17), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3, + ARM64_REG_X0, (16 * 18), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5, + ARM64_REG_X0, (16 * 19), + GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7, + ARM64_REG_X0, (16 * 20), + GUM_INDEX_SIGNED_OFFSET); + + /* x2 & x3 */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, + ARM64_REG_X0, (16 * 1), + GUM_INDEX_SIGNED_OFFSET); + /* x0 & x1 */ + gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X1, + ARM64_REG_X0, (16 * 0), + GUM_INDEX_SIGNED_OFFSET); + +} + +static void instrument_exit(GumArm64Writer *cw) { + + gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_X0, ARM64_REG_XZR); + gum_arm64_writer_put_call_address_with_arguments( + cw, GUM_ADDRESS(_exit), 1, GUM_ARG_REGISTER, ARM64_REG_X0); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + previous_pc = 0; + return ret; + +} + +static void instrument_afl_persistent_loop(GumArm64Writer *cw) { + + gum_arm64_writer_put_sub_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm64_writer_put_call_address_with_arguments( + cw, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); + gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, + GUM_RED_ZONE_SIZE); + +} + +static void persistent_prologue_hook(GumArm64Writer * cw, + struct arm64_regs *regs) { + + if (hook == NULL) return; + + gum_arm64_writer_put_sub_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X3, + GUM_ADDRESS(&__afl_fuzz_len)); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0); + + gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X3, ARM64_REG_X3, + G_MAXULONG); + + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0); + + gum_arm64_writer_put_call_address_with_arguments( + cw, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, GUM_ADDRESS(regs), + GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, ARM64_REG_X2, + GUM_ARG_REGISTER, ARM64_REG_X3); + + gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, + GUM_RED_ZONE_SIZE); + +} + +static void instrument_persitent_save_lr(GumArm64Writer *cw) { + + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE), + GUM_INDEX_PRE_ADJUST); + + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, + GUM_ADDRESS(&saved_lr)); + + gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_LR, ARM64_REG_X0, 0); + + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE, + GUM_INDEX_POST_ADJUST); } void persistent_prologue(GumStalkerOutput *output) { - UNUSED_PARAMETER(output); - FATAL("Persistent mode not supported on this architecture"); + /* + * SAVE REGS + * SAVE RET + * POP RET + * loop: + * CALL instrument_afl_persistent_loop + * TEST EAX, EAX + * JZ end: + * call hook (optionally) + * RESTORE REGS + * call original + * jmp loop: + * + * end: + * JMP SAVED RET + * + * original: + * INSTRUMENTED PERSISTENT FUNC + */ + + GumArm64Writer *cw = output->writer.arm64; + + gconstpointer loop = cw->code + 1; + + /* Stack must be 16-byte aligned per ABI */ + instrument_persitent_save_regs(cw, &saved_regs); + + /* loop: */ + gum_arm64_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_arm64_writer_put_cmp_reg_reg(cw, ARM64_REG_X0, ARM64_REG_XZR); + gum_arm64_writer_put_b_cond_label(cw, ARM64_CC_EQ, done); + + /* Optionally call the persistent hook */ + persistent_prologue_hook(cw, &saved_regs); + + instrument_persitent_restore_regs(cw, &saved_regs); + gconstpointer original = cw->code + 1; + /* call original */ + + gum_arm64_writer_put_bl_label(cw, original); + + /* jmp loop */ + gum_arm64_writer_put_b_label(cw, loop); + + /* done: */ + gum_arm64_writer_put_label(cw, done); + + instrument_exit(cw); + + /* original: */ + gum_arm64_writer_put_label(cw, original); + + instrument_persitent_save_lr(cw); + + if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); } } void persistent_epilogue(GumStalkerOutput *output) { - UNUSED_PARAMETER(output); - FATAL("Persistent mode not supported on this architecture"); + GumArm64Writer *cw = output->writer.arm64; + + if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); } + + gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, + persistent_ret_offset); + + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, + GUM_ADDRESS(&saved_lr)); + + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X0, 0); + + gum_arm64_writer_put_br_reg(cw, ARM64_REG_X0); } diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index 4cb960fc..858ad38e 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -306,8 +306,6 @@ void persistent_prologue(GumStalkerOutput *output) { if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } - gum_x86_writer_flush(cw); - } void persistent_epilogue(GumStalkerOutput *output) { diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index b30dfadf..0675edf4 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -246,8 +246,6 @@ void persistent_prologue(GumStalkerOutput *output) { if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } - gum_x86_writer_flush(cw); - } void persistent_epilogue(GumStalkerOutput *output) { diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 662fb6d5..0d7b9fb0 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -96,7 +96,6 @@ void stats_init(void) { void stats_vprint(int fd, char *format, va_list ap) { char buffer[4096] = {0}; - int ret; int len; if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } diff --git a/frida_mode/src/stats/stats_arm.c b/frida_mode/src/stats/stats_arm.c deleted file mode 100644 index 7eea7f91..00000000 --- a/frida_mode/src/stats/stats_arm.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "frida-gum.h" - -#include "debug.h" - -#include "stats.h" -#include "util.h" - -#if defined(__arm__) - -gboolean stats_is_supported_arch(void) { - - return FALSE; - -} - -size_t stats_data_size_arch(void) { - - FATAL("Stats not supported on this architecture"); - -} - -void stats_write_arch(void) { - - FATAL("Stats not supported on this architecture"); - -} - -void stats_collect_arch(const cs_insn *instr) { - - UNUSED_PARAMETER(instr); - FATAL("Stats not supported on this architecture"); - -} - -#endif - diff --git a/frida_mode/src/stats/stats_arm32.c b/frida_mode/src/stats/stats_arm32.c new file mode 100644 index 00000000..7eea7f91 --- /dev/null +++ b/frida_mode/src/stats/stats_arm32.c @@ -0,0 +1,36 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "stats.h" +#include "util.h" + +#if defined(__arm__) + +gboolean stats_is_supported_arch(void) { + + return FALSE; + +} + +size_t stats_data_size_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_write_arch(void) { + + FATAL("Stats not supported on this architecture"); + +} + +void stats_collect_arch(const cs_insn *instr) { + + UNUSED_PARAMETER(instr); + FATAL("Stats not supported on this architecture"); + +} + +#endif + diff --git a/frida_mode/test/cmplog/GNUmakefile b/frida_mode/test/cmplog/GNUmakefile index 40de6a09..4c71bb33 100644 --- a/frida_mode/test/cmplog/GNUmakefile +++ b/frida_mode/test/cmplog/GNUmakefile @@ -13,7 +13,7 @@ CMP_LOG_INPUT:=$(TEST_DATA_DIR)in QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -.PHONY: all 32 clean qemu frida format +.PHONY: all 32 clean qemu frida frida-nocmplog format all: $(TEST_CMPLOG_OBJ) make -C $(ROOT)frida_mode/ @@ -55,6 +55,15 @@ frida: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) -- \ $(TEST_CMPLOG_OBJ) @@ +frida-nocmplog: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) + $(ROOT)afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -Z \ + -- \ + $(TEST_CMPLOG_OBJ) @@ + debug: $(TEST_CMPLOG_OBJ) $(CMP_LOG_INPUT) gdb \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ diff --git a/frida_mode/test/cmplog/Makefile b/frida_mode/test/cmplog/Makefile index 606b43a5..7ca9a9a5 100644 --- a/frida_mode/test/cmplog/Makefile +++ b/frida_mode/test/cmplog/Makefile @@ -15,6 +15,10 @@ qemu: frida: @gmake frida + +frida-nocmplog: + @gmake frida-nocmplog + format: @gmake format diff --git a/frida_mode/test/cmplog/cmplog.c b/frida_mode/test/cmplog/cmplog.c index 99010645..ce5cf20e 100644 --- a/frida_mode/test/cmplog/cmplog.c +++ b/frida_mode/test/cmplog/cmplog.c @@ -53,7 +53,7 @@ int main(int argc, char **argv) { } -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__aarch64__) uint64_t x = 0; fread(&x, sizeof(x), 1, file); if (x != 0xCAFEBABECAFEBABE) { diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile index 08b271de..c971c724 100644 --- a/frida_mode/test/fasan/GNUmakefile +++ b/frida_mode/test/fasan/GNUmakefile @@ -46,7 +46,7 @@ ifeq "$(ARCH)" "x86_64" LIBASAN_FILE:=libclang_rt.asan-x86_64.so endif -ifeq "$(ARCH)" "aarch64" +ifeq "$(ARCH)" "arm64" LIBASAN_FILE:=libclang_rt.asan-aarch64.so endif @@ -110,7 +110,7 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) mkdir -p $@ $(TEST_DATA_FILE): | $(TEST_DATA_DIR) - echo -n "TUODATM" > $@ + echo -n "XUODATM" > $@ frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE) $(ROOT)afl-fuzz \ diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index df48d065..4c9d8a19 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -85,7 +85,7 @@ frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -- \ $(TESTINSTBIN) @@ -debug: $(TESTINSTR_DATA_FILE) +debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) gdb \ --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ --ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \ @@ -96,7 +96,7 @@ debug: $(TESTINSTR_DATA_FILE) --ex 'set disassembly-flavor intel' \ --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -run: $(TESTINSTR_DATA_FILE) +run: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile index ca6f0ff2..5af64822 100644 --- a/frida_mode/test/png/persistent/GNUmakefile +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -5,6 +5,7 @@ BUILD_DIR:=$(PWD)build/ TEST_BIN:=$(PWD)../build/test TEST_DATA_DIR:=../build/libpng/libpng-1.2.56/contrib/pngsuite/ +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)in QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out @@ -22,8 +23,7 @@ endif AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) -ARCH=$(shell uname -m) -ifeq "$(ARCH)" "aarch64" +ifeq "$(ARCH)" "arm64" AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000) endif @@ -46,6 +46,9 @@ all: $(BUILD_DIR): mkdir -p $@ +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + truncate -s 1M $@ + qemu: | $(BUILD_DIR) AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ AFL_QEMU_PERSISTENT_GPR=1 \ @@ -94,5 +97,12 @@ frida_entry: | $(BUILD_DIR) -- \ $(TEST_BIN) @@ +debug: $(AFLPP_DRIVER_DUMMY_INPUT) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/png/persistent/Makefile b/frida_mode/test/png/persistent/Makefile index cde0cf30..c2bd55f9 100644 --- a/frida_mode/test/png/persistent/Makefile +++ b/frida_mode/test/png/persistent/Makefile @@ -20,3 +20,6 @@ frida: frida_entry: @gmake frida_entry + +debug: + @gmake debug diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile index 82f08fa4..b17f3775 100644 --- a/frida_mode/test/png/persistent/hook/GNUmakefile +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -34,7 +34,7 @@ endif AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) -ifeq "$(ARCH)" "aarch64" +ifeq "$(ARCH)" "arm64" AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) endif @@ -124,7 +124,7 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) -debug: +debug: $(AFLPP_DRIVER_DUMMY_INPUT) echo $(AFL_FRIDA_PERSISTENT_ADDR) gdb \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ diff --git a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c index 059d438d..1542c0bf 100644 --- a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c +++ b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c @@ -82,6 +82,102 @@ void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, *arg2 = (void *)input_buf_len; } +#elif defined(__aarch64__) + +struct arm64_regs { + + uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; + + union { + + uint64_t x11; + uint32_t fp_32; + + }; + + union { + + uint64_t x12; + uint32_t ip_32; + + }; + + union { + + uint64_t x13; + uint32_t sp_32; + + }; + + union { + + uint64_t x14; + uint32_t lr_32; + + }; + + union { + + uint64_t x15; + uint32_t pc_32; + + }; + + union { + + uint64_t x16; + uint64_t ip0; + + }; + + union { + + uint64_t x17; + uint64_t ip1; + + }; + + uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; + + union { + + uint64_t x29; + uint64_t fp; + + }; + + union { + + uint64_t x30; + uint64_t lr; + + }; + + union { + + uint64_t x31; + uint64_t sp; + + }; + + // the zero register is not saved here ofc + + uint64_t pc; + + uint32_t cpsr; + + uint8_t vfp_zregs[32][16 * 16]; + uint8_t vfp_pregs[17][32]; + uint32_t vfp_xregs[16]; + +}; + +void afl_persistent_hook(struct arm64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->x0, input_buf, input_buf_len); + regs->x1 = input_buf_len; +} #else #pragma error "Unsupported architecture" diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 8ce5afb9..2d428e6d 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -6,7 +6,7 @@ ## 1) Introduction -! llvm_mode works with llvm versions 6.0 up to 12 ! +! llvm_mode works with llvm versions 3.8 up to 12 ! The code in this directory allows you to instrument programs for AFL using true compiler-level instrumentation, instead of the more crude diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 2089ce78..50117012 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -83,14 +83,15 @@ extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize); #endif // HAIKU -u8 __afl_area_initial[MAP_INITIAL_SIZE]; -u8 * __afl_area_ptr_dummy = __afl_area_initial; -u8 * __afl_area_ptr = __afl_area_initial; -u8 * __afl_area_ptr_backup = __afl_area_initial; -u8 * __afl_dictionary; -u8 * __afl_fuzz_ptr; -u32 __afl_fuzz_len_dummy; -u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy; +static u8 __afl_area_initial[MAP_INITIAL_SIZE]; +static u8 *__afl_area_ptr_dummy = __afl_area_initial; +static u8 *__afl_area_ptr_backup = __afl_area_initial; + +u8 * __afl_area_ptr = __afl_area_initial; +u8 * __afl_dictionary; +u8 * __afl_fuzz_ptr; +static u32 __afl_fuzz_len_dummy; +u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy; u32 __afl_final_loc; u32 __afl_map_size = MAP_SIZE; @@ -98,9 +99,9 @@ u32 __afl_dictionary_len; u64 __afl_map_addr; // for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: -int __afl_selective_coverage __attribute__((weak)); -int __afl_selective_coverage_start_off __attribute__((weak)); -int __afl_selective_coverage_temp = 1; +int __afl_selective_coverage __attribute__((weak)); +int __afl_selective_coverage_start_off __attribute__((weak)); +static int __afl_selective_coverage_temp = 1; #if defined(__ANDROID__) || defined(__HAIKU__) PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; @@ -147,7 +148,7 @@ static int __afl_dummy_fd[2] = {2, 2}; /* ensure we kill the child on termination */ -void at_exit(int signal) { +static void at_exit(int signal) { if (child_pid > 0) { kill(child_pid, SIGKILL); } @@ -179,7 +180,7 @@ void __afl_trace(const u32 x) { /* Error reporting to forkserver controller */ -void send_forkserver_error(int error) { +static void send_forkserver_error(int error) { u32 status; if (!error || error > 0xffff) return; @@ -629,6 +630,32 @@ static void __afl_unmap_shm(void) { } +#define write_error(text) write_error_with_location(text, __FILE__, __LINE__) + +void write_error_with_location(char *text, char* filename, int linenumber) { + + u8 * o = getenv("__AFL_OUT_DIR"); + char *e = strerror(errno); + + if (o) { + + char buf[4096]; + snprintf(buf, sizeof(buf), "%s/error.txt", o); + FILE *f = fopen(buf, "a"); + + if (f) { + + fprintf(f, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); + fclose(f); + + } + + } + + fprintf(stderr, "File %s, line %d: Error(%s): %s\n", filename, linenumber, text, e); + +} + #ifdef __linux__ static void __afl_start_snapshots(void) { @@ -655,7 +682,12 @@ static void __afl_start_snapshots(void) { if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { - if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); } + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("read to afl-fuzz"); + _exit(1); + + } if (__afl_debug) { @@ -724,7 +756,12 @@ static void __afl_start_snapshots(void) { } else { /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("reading from afl-fuzz"); + _exit(1); + + } } @@ -761,7 +798,12 @@ static void __afl_start_snapshots(void) { if (child_stopped && was_killed) { child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) _exit(1); + if (waitpid(child_pid, &status, 0) < 0) { + + write_error("child_stopped && was_killed"); + _exit(1); // TODO why exit? + + } } @@ -770,7 +812,12 @@ static void __afl_start_snapshots(void) { /* Once woken up, create a clone of our process. */ child_pid = fork(); - if (child_pid < 0) _exit(1); + if (child_pid < 0) { + + write_error("fork"); + _exit(1); + + } /* In child process: close fds, resume execution. */ @@ -810,9 +857,19 @@ static void __afl_start_snapshots(void) { /* In parent process: write PID to pipe, then wait for child. */ - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { + + write_error("write to afl-fuzz"); + _exit(1); - if (waitpid(child_pid, &status, WUNTRACED) < 0) _exit(1); + } + + if (waitpid(child_pid, &status, WUNTRACED) < 0) { + + write_error("waitpid"); + _exit(1); + + } /* In persistent mode, the child stops itself with SIGSTOP to indicate a successful run. In this case, we want to wake it up without forking @@ -822,7 +879,12 @@ static void __afl_start_snapshots(void) { /* Relay wait status to pipe, then loop back. */ - if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &status, 4) != 4) { + + write_error("writing to afl-fuzz"); + _exit(1); + + } } @@ -955,7 +1017,12 @@ static void __afl_start_forkserver(void) { } else { - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (read(FORKSRV_FD, &was_killed, 4) != 4) { + + write_error("read from afl-fuzz"); + _exit(1); + + } } @@ -992,7 +1059,12 @@ static void __afl_start_forkserver(void) { if (child_stopped && was_killed) { child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) _exit(1); + if (waitpid(child_pid, &status, 0) < 0) { + + write_error("child_stopped && was_killed"); + _exit(1); + + } } @@ -1001,7 +1073,12 @@ static void __afl_start_forkserver(void) { /* Once woken up, create a clone of our process. */ child_pid = fork(); - if (child_pid < 0) _exit(1); + if (child_pid < 0) { + + write_error("fork"); + _exit(1); + + } /* In child process: close fds, resume execution. */ @@ -1030,11 +1107,20 @@ static void __afl_start_forkserver(void) { /* In parent process: write PID to pipe, then wait for child. */ - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { + + write_error("write to afl-fuzz"); + _exit(1); + + } + + if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) { - if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) + write_error("waitpid"); _exit(1); + } + /* In persistent mode, the child stops itself with SIGSTOP to indicate a successful run. In this case, we want to wake it up without forking again. */ @@ -1043,7 +1129,12 @@ static void __afl_start_forkserver(void) { /* Relay wait status to pipe, then loop back. */ - if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1); + if (write(FORKSRV_FD + 1, &status, 4) != 4) { + + write_error("writing to afl-fuzz"); + _exit(1); + + } } @@ -1668,7 +1759,7 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { } -void __sanitizer_cov_trace_cost_cmp4(uint32_t arg1, uint32_t arg2) { +void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) { __cmplog_ins_hook4(arg1, arg2, 0); @@ -1990,3 +2081,4 @@ void __afl_coverage_interesting(u8 val, u32 id) { } +#undef write_error diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 6fe34ccd..94b77f7d 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -676,7 +676,7 @@ bool AFLCoverage::runOnModule(Module &M) { todo.push_back(MapPtrIdx); } else { - + */ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, #if LLVM_VERSION_MAJOR >= 13 diff --git a/src/afl-analyze.c b/src/afl-analyze.c index aabdbf1a..606254d9 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -55,12 +55,7 @@ #include #include -static s32 child_pid; /* PID of the tested program */ - -static u8 *trace_bits; /* SHM with instrumentation bitmap */ - -static u8 *in_file, /* Analyzer input test case */ - *prog_in; /* Targeted program input file */ +static u8 *in_file; /* Analyzer input test case */ static u8 *in_data; /* Input data for analysis */ @@ -73,20 +68,19 @@ static u64 orig_cksum; /* Original checksum */ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ -static s32 dev_null_fd = -1; /* FD to /dev/null */ - static bool edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = true; /* Use stdin for program input? */ -static volatile u8 stop_soon, /* Ctrl-C pressed? */ - child_timed_out; /* Child timed out? */ +static volatile u8 stop_soon; /* Ctrl-C pressed? */ static u8 *target_path; static u8 frida_mode; static u8 qemu_mode; static u32 map_size = MAP_SIZE; +static afl_forkserver_t fsrv = {0}; /* The forkserver */ + /* Constants used for describing byte behavior. */ #define RESP_NONE 0x00 /* Changing byte is a no-op. */ @@ -156,7 +150,7 @@ static void classify_counts(u8 *mem) { static inline u8 anything_set(void) { - u32 *ptr = (u32 *)trace_bits; + u32 *ptr = (u32 *)fsrv.trace_bits; u32 i = (map_size >> 2); while (i--) { @@ -173,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(prog_in); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -205,116 +199,29 @@ static void read_initial_file(void) { } -/* Write output file. */ - -static s32 write_to_file(u8 *path, u8 *mem, u32 len) { - - s32 ret; - - unlink(path); /* Ignore errors */ - - ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - - if (ret < 0) { PFATAL("Unable to create '%s'", path); } - - ck_write(ret, mem, len, path); - - lseek(ret, 0, SEEK_SET); - - return ret; - -} - /* Execute target application. Returns exec checksum, or 0 if program times out. */ -static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { - - static struct itimerval it; - int status = 0; - - s32 prog_in_fd; - u64 cksum; - - memset(trace_bits, 0, map_size); - MEM_BARRIER(); - - prog_in_fd = write_to_file(prog_in, mem, len); - - child_pid = fork(); - - if (child_pid < 0) { PFATAL("fork() failed"); } - - if (!child_pid) { - - struct rlimit r; - - if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 || - dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) { - - *(u32 *)trace_bits = EXEC_FAIL_SIG; - PFATAL("dup2() failed"); - - } - - close(dev_null_fd); - close(prog_in_fd); - - if (mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; - -#ifdef RLIMIT_AS - - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ +static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) { -#else - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ - -#endif /* ^RLIMIT_AS */ - - } - - r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - execv(target_path, argv); - - *(u32 *)trace_bits = EXEC_FAIL_SIG; - exit(0); + afl_fsrv_write_to_testcase(&fsrv, mem, len); + fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon); - } - - close(prog_in_fd); - - /* Configure timeout, wait for child, cancel timeout. */ - - child_timed_out = 0; - it.it_value.tv_sec = (exec_tmout / 1000); - it.it_value.tv_usec = (exec_tmout % 1000) * 1000; + if (ret == FSRV_RUN_ERROR) { - setitimer(ITIMER_REAL, &it, NULL); + FATAL("Error in forkserver"); - if (waitpid(child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); } + } else if (ret == FSRV_RUN_NOINST) { - child_pid = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; + FATAL("Target not instrumented"); - setitimer(ITIMER_REAL, &it, NULL); + } else if (ret == FSRV_RUN_NOBITS) { - MEM_BARRIER(); - - /* Clean up bitmap, analyze exit condition, etc. */ - - if (*(u32 *)trace_bits == EXEC_FAIL_SIG) { - - FATAL("Unable to execute '%s'", argv[0]); + FATAL("Failed to run target"); } - classify_counts(trace_bits); + classify_counts(fsrv.trace_bits); total_execs++; if (stop_soon) { @@ -326,21 +233,19 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { /* Always discard inputs that time out. */ - if (child_timed_out) { + if (fsrv.last_run_timed_out) { exec_hangs++; return 0; } - cksum = hash64(trace_bits, map_size, HASH_CONST); + u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST); - /* We don't actually care if the target is crashing or not, - except that when it does, the checksum should be different. */ + if (ret == FSRV_RUN_CRASH) { - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status))) { + /* We don't actually care if the target is crashing or not, + except that when it does, the checksum should be different. */ cksum ^= 0xffffffff; @@ -604,7 +509,7 @@ static void dump_hex(u32 len, u8 *b_data) { /* Actually analyze! */ -static void analyze(char **argv) { +static void analyze() { u32 i; u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0; @@ -630,16 +535,16 @@ static void analyze(char **argv) { code. */ in_data[i] ^= 0xff; - xor_ff = analyze_run_target(argv, in_data, in_len, 0); + xor_ff = analyze_run_target(in_data, in_len, 0); in_data[i] ^= 0xfe; - xor_01 = analyze_run_target(argv, in_data, in_len, 0); + xor_01 = analyze_run_target(in_data, in_len, 0); in_data[i] = (in_data[i] ^ 0x01) - 0x10; - sub_10 = analyze_run_target(argv, in_data, in_len, 0); + sub_10 = analyze_run_target(in_data, in_len, 0); in_data[i] += 0x20; - add_10 = analyze_run_target(argv, in_data, in_len, 0); + add_10 = analyze_run_target(in_data, in_len, 0); in_data[i] -= 0x10; /* Classify current behavior. */ @@ -712,7 +617,7 @@ static void handle_stop_sig(int sig) { (void)sig; stop_soon = 1; - if (child_pid > 0) { kill(child_pid, SIGKILL); } + afl_fsrv_killall(); } @@ -724,10 +629,10 @@ static void set_up_environment(char **argv) { char *afl_preload; char *frida_afl_preload = NULL; - dev_null_fd = open("/dev/null", O_RDWR); - if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + fsrv.dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - if (!prog_in) { + if (!fsrv.out_file) { u8 *use_dir = "."; @@ -738,10 +643,15 @@ static void set_up_environment(char **argv) { } - prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } + unlink(fsrv.out_file); + fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + + if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } + /* Set sane defaults... */ x = get_afl_env("ASAN_OPTIONS"); @@ -965,6 +875,8 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); + afl_fsrv_init(&fsrv); + while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) { switch (opt) { @@ -977,9 +889,9 @@ int main(int argc, char **argv_orig, char **envp) { case 'f': - if (prog_in) { FATAL("Multiple -f options not supported"); } - use_stdin = 0; - prog_in = optarg; + if (fsrv.out_file) { FATAL("Multiple -f options not supported"); } + fsrv.use_stdin = 0; + fsrv.out_file = ck_strdup(optarg); break; case 'e': @@ -1000,6 +912,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!strcmp(optarg, "none")) { mem_limit = 0; + fsrv.mem_limit = 0; break; } @@ -1038,6 +951,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.mem_limit = mem_limit; + } break; @@ -1057,6 +972,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.exec_tmout = exec_tmout; + break; case 'O': /* FRIDA mode */ @@ -1064,6 +981,7 @@ int main(int argc, char **argv_orig, char **envp) { if (frida_mode) { FATAL("Multiple -O options not supported"); } frida_mode = 1; + fsrv.frida_mode = frida_mode; break; @@ -1073,6 +991,8 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; } qemu_mode = 1; + fsrv.mem_limit = mem_limit; + fsrv.qemu_mode = qemu_mode; break; case 'U': @@ -1081,6 +1001,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; } unicorn_mode = 1; + fsrv.mem_limit = mem_limit; break; case 'W': /* Wine+QEMU mode */ @@ -1090,6 +1011,8 @@ int main(int argc, char **argv_orig, char **envp) { use_wine = 1; if (!mem_limit_given) { mem_limit = 0; } + fsrv.qemu_mode = qemu_mode; + fsrv.mem_limit = mem_limit; break; @@ -1108,6 +1031,7 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file) { usage(argv[0]); } map_size = get_map_size(); + fsrv.map_size = map_size; use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX"); @@ -1117,14 +1041,15 @@ int main(int argc, char **argv_orig, char **envp) { /* initialize cmplog_mode */ shm.cmplog_mode = 0; - trace_bits = afl_shm_init(&shm, map_size, 0); + atexit(at_exit_handler); setup_signal_handlers(); set_up_environment(argv); - target_path = find_binary(argv[optind]); - detect_file_args(argv + optind, prog_in, &use_stdin); + fsrv.target_path = find_binary(argv[optind]); + fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); + detect_file_args(argv + optind, fsrv.out_file, &use_stdin); if (qemu_mode) { @@ -1148,14 +1073,31 @@ int main(int argc, char **argv_orig, char **envp) { SAYF("\n"); + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { + + s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); + if (forksrv_init_tmout < 1) { + + FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); + + } + + fsrv.init_tmout = (u32)forksrv_init_tmout; + + } + + fsrv.kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + read_initial_file(); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", mem_limit, exec_tmout, edges_only ? ", edges only" : ""); - analyze_run_target(use_argv, in_data, in_len, 1); + afl_fsrv_start(&fsrv, use_argv, &stop_soon, false); + analyze_run_target(in_data, in_len, 1); - if (child_timed_out) { + if (fsrv.last_run_timed_out) { FATAL("Target binary times out (adjusting -t may help)."); @@ -1167,13 +1109,15 @@ int main(int argc, char **argv_orig, char **envp) { } - analyze(use_argv); + analyze(); OKF("We're done here. Have a nice day!\n"); - if (target_path) { ck_free(target_path); } - afl_shm_deinit(&shm); + afl_fsrv_deinit(&fsrv); + if (fsrv.target_path) { ck_free(fsrv.target_path); } + if (in_data) { ck_free(in_data); } + exit(0); diff --git a/src/afl-cc.c b/src/afl-cc.c index 486f7468..980e5d86 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -315,7 +315,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0, preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0, - have_c = 0; + have_c = 0, partial_linking = 0; cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); @@ -767,6 +767,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strcmp(cur, "-x")) x_set = 1; if (!strcmp(cur, "-E")) preprocessor_only = 1; if (!strcmp(cur, "-shared")) shared_linking = 1; + if (!strcmp(cur, "-Wl,-r")) partial_linking = 1; + if (!strcmp(cur, "-Wl,-i")) partial_linking = 1; if (!strcmp(cur, "-c")) have_c = 1; if (!strncmp(cur, "-O", 2)) have_o = 1; @@ -996,7 +998,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { switch (bit_mode) { case 0: - if (!shared_linking) + if (!shared_linking && !partial_linking) cc_params[cc_par_cnt++] = alloc_printf("%s/afl-compiler-rt.o", obj_path); if (lto_mode) @@ -1005,7 +1007,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { break; case 32: - if (!shared_linking) { + if (!shared_linking && !partial_linking) { cc_params[cc_par_cnt++] = alloc_printf("%s/afl-compiler-rt-32.o", obj_path); @@ -1026,7 +1028,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { break; case 64: - if (!shared_linking) { + if (!shared_linking && !partial_linking) { cc_params[cc_par_cnt++] = alloc_printf("%s/afl-compiler-rt-64.o", obj_path); @@ -1049,7 +1051,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } #if !defined(__APPLE__) && !defined(__sun) - if (!shared_linking) + if (!shared_linking && !partial_linking) cc_params[cc_par_cnt++] = alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path); #endif diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 88b5bc02..872e3a32 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -480,13 +480,22 @@ void read_foreign_testcases(afl_state_t *afl, int first) { for (iter = 0; iter < afl->foreign_sync_cnt; iter++) { - if (afl->foreign_syncs[iter].dir != NULL && - afl->foreign_syncs[iter].dir[0] != 0) { + if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) { if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); time_t mtime_max = 0; - u8 * name = strrchr(afl->foreign_syncs[iter].dir, '/'); - if (!name) { name = afl->foreign_syncs[iter].dir; } + + u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/'); + if (!name) { + + name = afl->foreign_syncs[iter].dir; + + } else { + + ++name; + + } + if (!strcmp(name, "queue") || !strcmp(name, "out") || !strcmp(name, "default")) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 4884b942..9648d795 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -766,9 +766,9 @@ void show_stats(afl_state_t *afl) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", time_tmp, tmp); - SAYF(bVR bH bSTOP cCYA - " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + SAYF(bVR bH bSTOP cCYA + " cycle progress " bSTG bH10 bH5 bH2 bH2 bH2 bHB bH bSTOP cCYA + " map coverage" bSTG bHT bH20 bH2 bVL "\n"); /* This gets funny because we want to print several variable-length variables together, but then cram them into a fixed-width field - so we need to @@ -778,13 +778,13 @@ void show_stats(afl_state_t *afl) { afl->queue_cur->favored ? "." : "*", afl->queue_cur->fuzz_level, ((double)afl->current_entry * 100) / afl->queued_paths); - SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); + SAYF(bV bSTOP " now processing : " cRST "%-18s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, t_byte_ratio); - SAYF(" map density : %s%-21s" bSTG bV "\n", + SAYF(" map density : %s%-19s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD : ((t_bytes < 200 && !afl->non_instrumented_mode) ? cPIN : cRST), @@ -793,23 +793,23 @@ void show_stats(afl_state_t *afl) { sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_paths), ((double)afl->cur_skipped_paths * 100) / afl->queued_paths); - SAYF(bV bSTOP " paths timed out : " cRST "%-16s " bSTG bV, tmp); + SAYF(bV bSTOP " paths timed out : " cRST "%-18s " bSTG bV, tmp); sprintf(tmp, "%0.02f bits/tuple", t_bytes ? (((double)t_bits) / t_bytes) : 0); - SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); + SAYF(bSTOP " count coverage : " cRST "%-19s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA - " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + SAYF(bVR bH bSTOP cCYA + " stage progress " bSTG bH10 bH5 bH2 bH2 bH2 bX bH bSTOP cCYA + " findings in depth " bSTG bH10 bH5 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); /* Yeah... it's still going on... halp? */ - SAYF(bV bSTOP " now trying : " cRST "%-20s " bSTG bV bSTOP - " favored paths : " cRST "%-22s" bSTG bV "\n", + SAYF(bV bSTOP " now trying : " cRST "%-22s " bSTG bV bSTOP + " favored paths : " cRST "%-20s" bSTG bV "\n", afl->stage_name, tmp); if (!afl->stage_max) { @@ -824,12 +824,12 @@ void show_stats(afl_state_t *afl) { } - SAYF(bV bSTOP " stage execs : " cRST "%-21s" bSTG bV bSTOP, tmp); + SAYF(bV bSTOP " stage execs : " cRST "%-23s" bSTG bV bSTOP, tmp); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_with_cov), ((double)afl->queued_with_cov) * 100 / afl->queued_paths); - SAYF(" new edges on : " cRST "%-22s" bSTG bV "\n", tmp); + SAYF(" new edges on : " cRST "%-20s" bSTG bV "\n", tmp); sprintf(tmp, "%s (%s%s unique)", u_stringify_int(IB(0), afl->total_crashes), u_stringify_int(IB(1), afl->unique_crashes), @@ -837,14 +837,14 @@ void show_stats(afl_state_t *afl) { if (afl->crash_mode) { - SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP - " new crashes : %s%-22s" bSTG bV "\n", + SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP + " new crashes : %s%-20s" bSTG bV "\n", u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp); } else { - SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP - " total crashes : %s%-22s" bSTG bV "\n", + SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP + " total crashes : %s%-20s" bSTG bV "\n", u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp); } @@ -856,12 +856,12 @@ void show_stats(afl_state_t *afl) { sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec), afl->stats_avg_exec < 20 ? "zzzz..." : "slow!"); - SAYF(bV bSTOP " exec speed : " cLRD "%-20s ", tmp); + SAYF(bV bSTOP " exec speed : " cLRD "%-22s ", tmp); } else { sprintf(tmp, "%s/sec", u_stringify_float(IB(0), afl->stats_avg_exec)); - SAYF(bV bSTOP " exec speed : " cRST "%-20s ", tmp); + SAYF(bV bSTOP " exec speed : " cRST "%-22s ", tmp); } @@ -869,13 +869,12 @@ void show_stats(afl_state_t *afl) { u_stringify_int(IB(1), afl->unique_tmouts), (afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); - SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-22s" bSTG bV "\n", tmp); + SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-20s" bSTG bV "\n", tmp); /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP - " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA - " path geometry " bSTG bH5 bH2 bVL "\n"); + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bH2 bHT bH10 bH2 + bH bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); if (unlikely(afl->custom_only)) { @@ -1017,9 +1016,10 @@ void show_stats(afl_state_t *afl) { if (unlikely(afl->afl_env.afl_custom_mutator_library)) { strcat(tmp, " "); - strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_PYTHON])); + strcat(tmp, u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR])); strcat(tmp, "/"); - strcat(tmp, u_stringify_int(IB(3), afl->stage_cycles[STAGE_PYTHON])); + strcat(tmp, + u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); strcat(tmp, ","); } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 196547f4..9a3780fb 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -575,7 +575,6 @@ int main(int argc, char **argv_orig, char **envp) { } afl->sync_id = ck_strdup(optarg); - afl->skip_deterministic = 0; // force deterministic fuzzing afl->old_seed_selection = 1; // force old queue walking seed selection afl->disable_trim = 1; // disable trimming @@ -1206,6 +1205,8 @@ int main(int argc, char **argv_orig, char **envp) { } + setenv("__AFL_OUT_DIR", afl->out_dir, 1); + if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; } if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) { diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 1152cc4e..7cdc83cb 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -4,14 +4,6 @@ $ECHO "$BLUE[*] Testing: llvm_mode, afl-showmap, afl-fuzz, afl-cmin and afl-tmin" test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { - # on FreeBSD need to set AFL_CC - test `uname -s` = 'FreeBSD' && { - if type clang >/dev/null; then - export AFL_CC=`command -v clang` - else - export AFL_CC=`$LLVM_CONFIG --bindir`/clang - fi - } ../afl-clang-fast -o test-instr.plain ../test-instr.c > /dev/null 2>&1 AFL_HARDEN=1 ../afl-clang-fast -o test-compcov.harden test-compcov.c > /dev/null 2>&1 test -e test-instr.plain && { -- cgit 1.4.1 From a7340a1ac6c6165c8eb390a503758104c0d85bcb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 10 Jun 2021 10:25:37 +0200 Subject: fix AFL_CAL_FAST --- docs/Changelog.md | 1 + docs/env_variables.md | 4 +--- include/afl-fuzz.h | 4 +--- src/afl-analyze.c | 9 +++++---- src/afl-fuzz-run.c | 5 +++-- src/afl-fuzz-state.c | 9 +++++++-- src/afl-fuzz.c | 9 --------- 7 files changed, 18 insertions(+), 23 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6c851460..29ef69f9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why + - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - afl-cc - support partial linking - We do support llvm versions from 3.8 again diff --git a/docs/env_variables.md b/docs/env_variables.md index 38a67bc7..e058f377 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -108,9 +108,6 @@ make fairly broad use of environmental variables instead: - Setting `AFL_QUIET` will prevent afl-cc and afl-as banners from being displayed during compilation, in case you find them distracting. - - Setting `AFL_CAL_FAST` will speed up the initial calibration, if the - application is very slow. - ## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset @@ -386,6 +383,7 @@ checks or alter some of the more exotic semantics of the tool: - `AFL_FAST_CAL` keeps the calibration stage about 2.5x faster (albeit less precise), which can help when starting a session against a slow target. + `AFL_CAL_FAST` works too. - The CPU widget shown at the bottom of the screen is fairly simplistic and may complain of high load prematurely, especially on systems with low core diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4aba3bdf..2920f905 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -478,9 +478,7 @@ typedef struct afl_state { u32 hang_tmout; /* Timeout used for hang det (ms) */ - u8 cal_cycles, /* Calibration cycles defaults */ - cal_cycles_long, /* Calibration cycles defaults */ - havoc_stack_pow2, /* HAVOC_STACK_POW2 */ + u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */ no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 606254d9..dbf2920f 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -167,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(fsrv.out_file); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -643,12 +643,14 @@ static void set_up_environment(char **argv) { } - fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = + alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } unlink(fsrv.out_file); - fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fsrv.out_fd = + open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } @@ -1118,7 +1120,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv.target_path) { ck_free(fsrv.target_path); } if (in_data) { ck_free(in_data); } - exit(0); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 493735ff..758bad25 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -314,7 +314,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, ++q->cal_failed; afl->stage_name = "calibration"; - afl->stage_max = afl->fast_cal ? 3 : CAL_CYCLES; + afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES; /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ @@ -403,7 +403,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = + afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0658070e..b832c11e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -96,8 +96,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->splicing_with = -1; /* Splicing with which test case? */ afl->cpu_to_bind = -1; afl->havoc_stack_pow2 = HAVOC_STACK_POW2; - afl->cal_cycles = CAL_CYCLES; - afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; afl->exit_on_time = 0; afl->stats_update_freq = 1; @@ -341,6 +339,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_cal_fast = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_FAST_CAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_STATSD", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9a3780fb..e9a67ac5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1276,7 +1276,6 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; } if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; } - if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; } if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; } if (afl->afl_env.afl_autoresume) { @@ -1489,14 +1488,6 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; } - if (afl->afl_env.afl_cal_fast) { - - /* Use less calibration cycles, for slow applications */ - afl->cal_cycles = 3; - afl->cal_cycles_long = 5; - - } - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ -- cgit 1.4.1 From 63504f7b7e9f17145b63ba7d5a9e837e17ccb3a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 10:44:06 +0200 Subject: fix cmplog screen update crash --- docs/Changelog.md | 3 +- src/afl-common.c | 2 ++ src/afl-fuzz-redqueen.c | 91 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 33 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29ef69f9..97903c2a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,9 +9,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.14a (release) - - Fix for llvm 13 - afl-fuzz: - fix -F when a '/' was part of the parameter + - fixed a crash for cmplog for very slow inputs - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why @@ -21,6 +21,7 @@ sending a mail to . - We do support llvm versions from 3.8 again - afl_analyze - fix timeout handling and support forkserver + - Fix for llvm 13 - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance diff --git a/src/afl-common.c b/src/afl-common.c index c61ce3d8..9ca2b3e8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -751,6 +751,8 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { } +/* Get unix time in milliseconds */ + u64 get_cur_time(void) { struct timeval tv; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index b41ffa88..268f726c 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -252,7 +252,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 start_time = get_cur_time(); #endif - u32 screen_update = 1000000 / afl->queue_cur->exec_us; + u32 screen_update; u64 orig_hit_cnt, new_hit_cnt, exec_cksum; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -261,6 +261,24 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, afl->stage_max = (len << 1); afl->stage_cur = 0; + if (likely(afl->queue_cur->exec_us)) { + + if (likely((100000 / 2) >= afl->queue_cur->exec_us)) { + + screen_update = 100000 / afl->queue_cur->exec_us; + + } else { + + screen_update = 1; + + } + + } else { + + screen_update = 100000; + + } + // in colorization we do not classify counts, hence we have to calculate // the original checksum. if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) { @@ -905,17 +923,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..." s64 diff = pattern - b_val; s64 o_diff = o_pattern - o_b_val; - /* - fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, - h->shape + 1, o_pattern, o_b_val, o_diff); - fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, - b_val, diff);*/ + /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, + h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, + b_val, diff); */ if (diff == o_diff && diff) { // this could be an arithmetic transformation u64 new_repl = (u64)((s64)repl - diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -935,15 +952,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, diff = pattern ^ b_val; s64 o_diff = o_pattern ^ o_b_val; - /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (diff == o_diff && diff) { // this could be a XOR transformation u64 new_repl = (u64)((s64)repl ^ diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -982,15 +1001,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1029,15 +1050,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl | (0x2020202020202020 & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1383,7 +1406,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - //#endif /* CMPLOG_SOLVE_ARITHMETIC + //#endif /* + // CMPLOG_SOLVE_ARITHMETIC return 0; @@ -2152,7 +2176,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, memcpy(buf + idx, tmp, i + 1); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, *status); + // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, + // *status); } @@ -2235,7 +2260,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, for (j = 0; j <= i; j++) buf[idx + j] = repl[j] - arith_val[j]; if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status); + // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, + // *status); } @@ -2328,16 +2354,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, /* struct cmp_header *hh = &afl->orig_cmp_map->headers[key]; - fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id, - h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x", - o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr, - "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u - o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v0[j]); - fprintf(stderr, " o1="); - for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v1[j]); - fprintf(stderr, "\n"); + fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, + h->id, h->shape, h->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v0[j]); + fprintf(stderr, " v1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v1[j]); + fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=", + hh->hits, hh->id, hh->shape, hh->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v0[j]); + fprintf(stderr, " o1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v1[j]); + fprintf(stderr, "\n"); */ t = taint; -- cgit 1.4.1 From 581593ccab9516fbe372355fdb06180a5357e813 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 11:05:57 +0200 Subject: code format --- docs/Changelog.md | 4 +- docs/FAQ.md | 21 ++++ instrumentation/split-compares-pass.so.cc | 184 +++++++++++++++++++++++++++++- 3 files changed, 206 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 97903c2a..0e2ce27d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,11 +17,13 @@ sending a mail to . an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - afl-cc + - Update to COMPCOV/laf-intel that speeds up the instrumentation process + a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix for llvm 13 - support partial linking - We do support llvm versions from 3.8 again - afl_analyze - fix timeout handling and support forkserver - - Fix for llvm 13 - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance diff --git a/docs/FAQ.md b/docs/FAQ.md index 714d50eb..ab0abe6c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -3,6 +3,7 @@ ## Contents * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) + * [I got a weird compile error from clang](#i-got-a-weird-compile-error-from-clang) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) @@ -35,6 +36,26 @@ flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) +## I got a weird compile error from clang + +If you see this kind of error when trying to instrument a target with afl-cc/ +afl-clang-fast/afl-clang-lto: +``` +/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv +clang-13: error: unable to execute command: No such file or directory +clang-13: error: clang frontend command failed due to signal (use -v to see invocation) +clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad) +Target: x86_64-unknown-linux-gnu +Thread model: posix +InstalledDir: /prg/tmp/llvm-project/build/bin +clang-13: note: diagnostic msg: +******************** +``` +Then this means that your OS updated the clang installation from an upgrade +package and because of that the afl++ llvm plugins do not match anymore. + +Solution: `git pull ; make clean install` of afl++ + ## How to improve the fuzzing speed? 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 6eb9050c..10f86a66 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -54,20 +54,25 @@ using namespace llvm; namespace { class SplitComparesTransform : public ModulePass { + public: static char ID; SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { + initInstrumentList(); + } bool runOnModule(Module &M) override; #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { + #else const char *getPassName() const override { #endif return "AFL_SplitComparesTransform"; + } private: @@ -98,30 +103,47 @@ class SplitComparesTransform : public ModulePass { /// print an error to llvm's errs stream, but only if not ordered to be quiet void reportError(const StringRef msg, Instruction *I, Module &M) { + if (!be_quiet) { + errs() << "[AFL++ SplitComparesTransform] ERROR: " << msg << "\n"; if (debug) { + if (I) { + errs() << "Instruction = " << *I << "\n"; if (auto BB = I->getParent()) { + if (auto F = BB->getParent()) { + if (F->hasName()) { + errs() << "|-> in function " << F->getName() << " "; + } + } + } + } + auto n = M.getName(); if (n.size() > 0) { errs() << "in module " << n << "\n"; } + } + } + } bool isSupportedBitWidth(unsigned bitw) { + // IDK whether the icmp code works on other bitwidths. I guess not? So we // try to avoid dealing with other weird icmp's that llvm might use (looking // at you `icmp i0`). switch (bitw) { + case 8: case 16: case 32: @@ -131,8 +153,11 @@ class SplitComparesTransform : public ModulePass { return true; default: return false; + } + } + }; } // namespace @@ -142,6 +167,7 @@ char SplitComparesTransform::ID = 0; /// This function splits FCMP instructions with xGE or xLE predicates into two /// FCMP instructions with predicate xGT or xLT and EQ bool SplitComparesTransform::simplifyFPCompares(Module &M) { + LLVMContext & C = M.getContext(); std::vector fcomps; IntegerType * Int1Ty = IntegerType::getInt1Ty(C); @@ -149,18 +175,23 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* iterate over all functions, bbs and instruction and add * all integer comparisons with >= and <= predicates to the icomps vector */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast(&IN))) { + if (enableFPSplit && (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -173,16 +204,22 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return false; } /* transform for floating point */ for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -195,6 +232,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::FCMP_UGE: new_pred = CmpInst::FCMP_UGT; break; @@ -209,6 +247,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { break; default: // keep the compiler happy continue; + } /* split before the fcmp instruction */ @@ -252,9 +291,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* replace the old FcmpInst with our new and shiny PHI inst */ BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); + } return true; + } /// This function splits ICMP instructions with xGE or xLE predicates into two @@ -262,6 +303,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, Module & M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -278,6 +320,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::ICMP_UGE: new_pred = CmpInst::ICMP_UGT; break; @@ -292,6 +335,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, break; default: // keep the compiler happy return false; + } /* split before the icmp instruction */ @@ -338,6 +382,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, worklist.push_back(icmp_eq); return true; + } /// Simplify a signed comparison operator by splitting it into a unsigned and @@ -345,6 +390,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, /// the worklist passed as a reference. bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -365,10 +411,13 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Predicate new_pred; if (pred == CmpInst::ICMP_SGT) { + new_pred = CmpInst::ICMP_UGT; } else { + new_pred = CmpInst::ICMP_ULT; + } BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); @@ -391,6 +440,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, BasicBlock *sign_bb = BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_SGT) { + /* if we check for > and the op0 positive and op1 negative then the final * result is true. if op0 negative and op1 pos, the cmp must result * in false @@ -399,9 +449,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); } else { + /* just the inverse of the above statement */ icmp_inv_sig_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); + } sign_bb->getInstList().push_back(icmp_inv_sig_cmp); @@ -439,12 +491,15 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, // worklist.push_back(icmp_inv_sig_cmp); return true; + } bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, CmpWorklist &worklist) { + auto pred = cmp_inst->getPredicate(); switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: case CmpInst::ICMP_UGT: @@ -453,6 +508,7 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, default: // unsupported predicate! return false; + } auto op0 = cmp_inst->getOperand(0); @@ -461,14 +517,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // get bitwidth by checking the bitwidth of the first operator IntegerType *intTyOp0 = dyn_cast(op0->getType()); if (!intTyOp0) { + // not an integer type return false; + } unsigned bitw = intTyOp0->getBitWidth(); if (bitw == target_bitwidth) { + // already the target bitwidth so we have to do nothing here. return true; + } LLVMContext &C = M.getContext(); @@ -497,15 +557,17 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, /* now we have to destinguish between == != and > < */ switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: { + /* transformation for == and != icmps */ /* create a compare for the lower half of the original operands */ BasicBlock *cmp_low_bb = BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); - Value *op0_low, *op1_low; + Value * op0_low, *op1_low; IRBuilder<> Builder(cmp_low_bb); op0_low = Builder.CreateTrunc(op0, NewIntType); @@ -519,11 +581,16 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, auto term = bb->getTerminator(); BranchInst *br = nullptr; if (pred == CmpInst::ICMP_EQ) { + br = 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); + } + term->eraseFromParent(); /* create the PHI and connect the edges accordingly */ @@ -531,32 +598,43 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(icmp_low, cmp_low_bb); Value *val = nullptr; if (pred == CmpInst::ICMP_EQ) { + val = ConstantInt::get(Int1Ty, 0); + } else { + /* CmpInst::ICMP_NE */ val = ConstantInt::get(Int1Ty, 1); + } + PN->addIncoming(val, icmp_high->getParent()); break; + } + case CmpInst::ICMP_UGT: case CmpInst::ICMP_ULT: { + /* transformations for < and > */ /* create a basic block which checks for the inverse predicate. * if this is true we can go to the end if not we have to go to the * bb which checks the lower half of the operands */ Instruction *op0_low, *op1_low; - CmpInst *icmp_inv_cmp = nullptr; + CmpInst * icmp_inv_cmp = nullptr; BasicBlock * inv_cmp_bb = BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_UGT) { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, op0_high, op1_high); } else { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, op0_high, op1_high); + } inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); @@ -585,9 +663,12 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb); break; + } + default: return false; + } BasicBlock::iterator ii(cmp_inst); @@ -597,14 +678,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // bitwidth we recursivly split the low and high parts again until we have // target bitwidth. if ((bitw / 2) > target_bitwidth) { + worklist.push_back(icmp_high); worklist.push_back(icmp_low); + } return true; + } bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { + CmpWorklist worklist; auto op0 = I->getOperand(0); @@ -625,23 +710,35 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { I->getPredicate() == CmpInst::ICMP_SGE || I->getPredicate() == CmpInst::ICMP_ULE || I->getPredicate() == CmpInst::ICMP_SLE) { + if (!simplifyOrEqualsCompare(I, M, worklist)) { + reportError( "Failed to simplify inequality or equals comparison " "(UGE,SGE,ULE,SLE)", I, M); + } + } else if (I->getPredicate() == CmpInst::ICMP_SGT || + I->getPredicate() == CmpInst::ICMP_SLT) { + if (!simplifySignedCompare(I, M, worklist)) { + reportError("Failed to simplify signed comparison (SGT,SLT)", I, M); + } + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("simpliyfing compare lead to broken function", nullptr, M); + } + #endif // the simplification methods replace the original CmpInst and push the @@ -650,27 +747,38 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { if (worklist.size() == 0) { worklist.push_back(I); } while (!worklist.empty()) { + CmpInst *cmp = worklist.pop_back_val(); // we split the simplified compares into comparisons with smaller bitwidths // if they are larger than our target_bitwidth. if (bitw > target_bitwidth) { + if (!splitCompare(cmp, M, worklist)) { + reportError("Failed to split comparison", cmp, M); + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("splitting compare lead to broken function", nullptr, M); + } + #endif + } + } count++; return true; + } size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { + --in; in |= in >> 1; in |= in >> 2; @@ -678,10 +786,12 @@ size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { // in |= in >> 8; // in |= in >> 16; return in + 1; + } /* splits fcmps into two nested fcmps with sign compare and the rest */ size_t SplitComparesTransform::splitFPCompares(Module &M) { + size_t count = 0; LLVMContext &C = M.getContext(); @@ -693,9 +803,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* define unions with floating point and (sign, exponent, mantissa) triples */ if (dl.isLittleEndian()) { + } else if (dl.isBigEndian()) { + } else { + return count; + } #endif @@ -705,13 +819,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* get all EQ, NE, GT, and LT fcmps. if the other two * functions were executed only these four predicates should exist */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast(&IN))) { + if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_ONE || @@ -720,6 +838,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || selectcmpInst->getPredicate() == CmpInst::FCMP_OLT) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -731,10 +850,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return count; } @@ -742,6 +866,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { IntegerType *Int1Ty = IntegerType::getInt1Ty(C); for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -866,6 +991,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), t_e1); if (sizeInBits - precision < exTySizeBytes * 8) { + m_e0 = BinaryOperator::Create( Instruction::And, t_e0, ConstantInt::get(t_e0->getType(), mask_exponent)); @@ -878,8 +1004,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), m_e1); } else { + m_e0 = t_e0; m_e1 = t_e1; + } /* compare the exponents of the operands */ @@ -887,6 +1015,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *icmp_exponent_result; BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_exponent_result = @@ -956,6 +1085,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } signequal2_bb->getInstList().insert( @@ -963,9 +1093,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent_result); { + term = signequal2_bb->getTerminator(); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* if the exponents are satifying the compare do a fraction cmp in @@ -988,9 +1120,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } term->eraseFromParent(); + } /* isolate the mantissa aka fraction */ @@ -998,6 +1132,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { bool needTrunc = IntFractionTy->getPrimitiveSizeInBits() < op_size; if (precision - 1 < frTySizeBytes * 8) { + Instruction *m_f0, *m_f1; m_f0 = BinaryOperator::Create( Instruction::And, b_op0, @@ -1011,6 +1146,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), m_f1); if (needTrunc) { + t_f0 = new TruncInst(m_f0, IntFractionTy); t_f1 = new TruncInst(m_f1, IntFractionTy); middle_bb->getInstList().insert( @@ -1019,12 +1155,16 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = m_f0; t_f1 = m_f1; + } } else { + if (needTrunc) { + t_f0 = new TruncInst(b_op0, IntFractionTy); t_f1 = new TruncInst(b_op1, IntFractionTy); middle_bb->getInstList().insert( @@ -1033,9 +1173,12 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = b_op0; t_f1 = b_op1; + } + } /* compare the fractions of the operands */ @@ -1043,6 +1186,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock * middle2_bb = middle_bb; PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_fraction_result = @@ -1065,6 +1209,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_UGT: case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: { + Instruction *icmp_fraction_result2; middle2_bb = middle_bb->splitBasicBlock( @@ -1077,6 +1222,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT || FcmpInst->getPredicate() == CmpInst::FCMP_UGT) { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); @@ -1085,12 +1231,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); } else { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); positive_bb->getInstList().push_back( icmp_fraction_result2 = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); + } BranchInst::Create(middle2_bb, negative_bb); @@ -1110,11 +1258,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { default: continue; + } PHINode *PN = PHINode::Create(Int1Ty, 3, ""); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ @@ -1153,17 +1303,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); ++count; + } return count; + } bool SplitComparesTransform::runOnModule(Module &M) { + char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { target_bitwidth = atoi(bitw_env); } @@ -1172,6 +1326,7 @@ bool SplitComparesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) { + errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " "heiko@hexco.de (splitting icmp to " << target_bitwidth << " bit)\n"; @@ -1179,10 +1334,13 @@ bool SplitComparesTransform::runOnModule(Module &M) { if (getenv("AFL_DEBUG") != NULL && !debug) { debug = 1; } } else { + be_quiet = 1; + } if (enableFPSplit) { + count = splitFPCompares(M); /* @@ -1195,55 +1353,76 @@ bool SplitComparesTransform::runOnModule(Module &M) { */ simplifyFPCompares(M); + } std::vector worklist; /* iterate over all functions, bbs and instruction search for all integer * compare instructions. Save them into the worklist for later. */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + if (auto CI = dyn_cast(&IN)) { + auto op0 = CI->getOperand(0); auto op1 = CI->getOperand(1); if (!op0 || !op1) { return false; } auto iTy1 = dyn_cast(op0->getType()); if (iTy1 && isa(op1->getType())) { + unsigned bitw = iTy1->getBitWidth(); if (isSupportedBitWidth(bitw)) { worklist.push_back(CI); } + } + } + } + } + } // now that we have a list of all integer comparisons we can start replacing // them with the splitted alternatives. for (auto CI : worklist) { + simplifyAndSplit(CI, M); + } bool brokenDebug = false; if (verifyModule(M, &errs(), &brokenDebug)) { + reportError( "Module Verifier failed! Consider reporting a bug with the AFL++ " "project.", nullptr, M); + } if (brokenDebug) { + reportError("Module Verifier reported broken Debug Infos - Stripping!", nullptr, M); StripDebugInfo(M); + } + return true; + } static void registerSplitComparesPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(new SplitComparesTransform()); + } static RegisterStandardPasses RegisterSplitComparesPass( @@ -1262,3 +1441,4 @@ static RegisterPass X("splitcompares", "AFL++ split compares", true /* Only looks at CFG */, true /* Analysis Pass */); + -- cgit 1.4.1 From d2e256e73a2146b125c316e66a96f0215414411b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 14:39:35 +0200 Subject: fix to instrument global c++ namespace functions --- docs/Changelog.md | 3 ++- instrumentation/afl-llvm-common.cc | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0e2ce27d..d3863c74 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,9 +19,10 @@ sending a mail to . - afl-cc - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix to instrument global functions in c++ - Fix for llvm 13 - support partial linking - - We do support llvm versions from 3.8 again + - We do support llvm versions from 3.8 to 5.0 again - afl_analyze - fix timeout handling and support forkserver - ensure afl-compiler-rt is built for gcc_module diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index af32e2f9..3239ea91 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -96,9 +96,8 @@ bool isIgnoreFunction(const llvm::Function *F) { static constexpr const char *ignoreSubstringList[] = { - "__asan", "__msan", "__ubsan", "__lsan", - "__san", "__sanitize", "__cxx", "_GLOBAL__", - "DebugCounter", "DwarfDebug", "DebugLoc" + "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize", + "__cxx", "DebugCounter", "DwarfDebug", "DebugLoc" }; -- cgit 1.4.1 From dfff952f5371b184b021fda3a81fbd3fd6b205ac Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 15:07:04 +0200 Subject: update changelog --- docs/Changelog.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index d3863c74..8738ffa3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,20 +13,23 @@ sending a mail to . - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs - removed implied -D determinstic from -M main - - if the target becomes unavailable check out out/default/error.txt for - an indicator why + - if the target becomes unavailable check out out/default/error.txt + for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - - afl-cc - - Update to COMPCOV/laf-intel that speeds up the instrumentation process - a lot - thanks to Michael Rodler/f0rki for the PR! - - Fix to instrument global functions in c++ + - afl-cc: + - Update to COMPCOV/laf-intel that speeds up the instrumentation + process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking - We do support llvm versions from 3.8 to 5.0 again - - afl_analyze - - fix timeout handling and support forkserver + - frida_mode: + - fix for cmplog + - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - afl_analyze: + - fix timeout handling + - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module - - afl-analyze now uses the forkserver for increased performance ### Version ++3.13c (release) -- cgit 1.4.1 From 8c1b0aba5f196e3ae58399b660442e77613c5558 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 15:32:52 +0200 Subject: document frida changes --- README.md | 28 ++++++++++++++-------------- docs/Changelog.md | 2 ++ 2 files changed, 16 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index bc547b3c..f66eb288 100644 --- a/README.md +++ b/README.md @@ -88,20 +88,20 @@ behaviours and defaults: with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. - | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | - | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| - | Threadsafe counters | | x(3) | | | | | - | NeverZero | x86[_64]| x(1) | x | x | x | x | - | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | - | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | x86[_64] | x86[_64]/arm[64] | | - | Selective Instrumentation| | x | x | x | x | | - | Non-Colliding Coverage | | x(4) | | | (x)(5) | | - | Ngram prev_loc Coverage | | x(6) | | | | | - | Context Coverage | | x(6) | | | | | - | Auto Dictionary | | x(7) | | | | | - | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | - | Shared Memory Testcases | | x | x | x | x | x | + | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | + | -------------------------|:-------:|:---------:|:----------:|:----------------:|:----------------:|:----------------:| + | Threadsafe counters | | x(3) | | | | | + | NeverZero | x86[_64]| x(1) | x | x | x | x | + | Persistent Mode | | x | x | x86[_64]/arm[64] | x86[_64]/arm[64] | x | + | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | + | CmpLog | | x | | x86[_64]/arm[64] | x86[_64]/arm[64] | | + | Selective Instrumentation| | x | x | x | x | | + | Non-Colliding Coverage | | x(4) | | | (x)(5) | | + | Ngram prev_loc Coverage | | x(6) | | | | | + | Context Coverage | | x(6) | | | | | + | Auto Dictionary | | x(7) | | | | | + | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | + | Shared Memory Testcases | | x | x | x | x | x | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin diff --git a/docs/Changelog.md b/docs/Changelog.md index eebcaed4..9f70535a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,6 +26,8 @@ sending a mail to . - frida_mode: - fix for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - feature parity of aarch64 with intel now (persistent, cmplog, + in-memory testcases, asan) - afl_analyze: - fix timeout handling - add forkserver support for better performance -- cgit 1.4.1 From 7bcd4e290111ca81d6d58d1b70696e9e9aaa5ac1 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 14 Jun 2021 23:48:47 +0200 Subject: push to stable (#973) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release * back push (#952) * Dev (#949) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters Co-authored-by: van Hauser Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic * v3.13c release (#950) * use atomic read-modify-write increment for LLVM CLASSIC * Change other LLVM modes to atomic increments * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * work in progress: not working correctly yet * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * still not working * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * first working NeverZero implementation * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * add some comments * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file * push to stable (#931) (#932) * sync (#886) * Create FUNDING.yml * Update FUNDING.yml * moved custom_mutator examples * unicorn speedtest makefile cleanup * fixed example location * fix qdbi * update util readme * Frida persistent (#880) * Added x64 support for persistent mode (function call only), in-memory teest cases and complog * Review changes, fix NeverZero and code to parse the .text section of the main executable. Excluded ranges TBC * Various minor fixes and finished support for AFL_INST_LIBS * Review changes Co-authored-by: Your Name * nits * fix frida mode * Integer overflow/underflow fixes in libdislocator (#889) * libdislocator: fixing integer overflow in 'max_mem' variable and setting 'max_mem' type to 'size_t' * libdislocator: fixing potential integer underflow in 'total_mem' variable due to its different values in different threads * Bumped warnings up to the max and fixed remaining issues (#890) Co-authored-by: Your Name * nits * frida mode - support non-pie * nits * nit * update grammar mutator * Fixes for aarch64, OSX and other minor issues (#891) Co-authored-by: Your Name * nits * nits * fix PCGUARD, build aflpp_driver with fPIC * Added representative fuzzbench test and test for libxml (#893) * Added representative fuzzbench test and test for libxml * Added support for building FRIDA from source with FRIDA_SOURCE=1 Co-authored-by: Your Name * nits * update changelog * typos * fixed potential double free in custom trim (#881) * error handling, freeing mem * frida: complog -> cmplog * fix statsd writing * let aflpp_qemu_driver_hook.so build fail gracefully * fix stdin trimming * Support for AFL_ENTRYPOINT (#898) Co-authored-by: Your Name * remove the input file .cur_input at the end of the fuzzing, if AFL_TMPDIR is used * reverse push (#901) * Create FUNDING.yml * Update FUNDING.yml * disable QEMU static pie Co-authored-by: Andrea Fioraldi * clarify that no modifications are required. * add new test for frida_mode (please review) * typos * fix persistent mode (64-bit) * set ARCH for linux intel 32-bit for frida-gum-devkit * prepare for 32-bit support (later) * not on qemu 3 anymore * unicorn mips fixes * instrumentation further move to C++11 (#900) * unicorn fixes * more unicorn fixes * Fix memory errors when trim causes testcase growth (#881) (#903) * Revert "fixed potential double free in custom trim (#881)" This reverts commit e9d2f72382cab75832721d859c3e731da071435d. * Revert "fix custom trim for increasing data" This reverts commit 86a8ef168dda766d2f25f15c15c4d3ecf21d0667. * Fix memory errors when trim causes testcase growth Modify trim_case_custom to avoid writing into in_buf because some custom mutators can cause the testcase to grow rather than shrink. Instead of modifying in_buf directly, we write the update out to the disk when trimming is complete, and then the caller is responsible for refreshing the in-memory buffer from the file. This is still a bit sketchy because it does need to modify q->len in order to notify the upper layers that something changed, and it could end up telling upper layer code that the q->len is *bigger* than the buffer (q->testcase_buf) that contains it, which is asking for trouble down the line somewhere... * Fix an unlikely situation Put back some `unlikely()` calls that were in the e9d2f72382cab75832721d859c3e731da071435d commit that was reverted. * typo * Exit on time (#904) * Variable AFL_EXIT_ON_TIME description has been added. Variables AFL_EXIT_ON_TIME and afl_exit_on_time has been added. afl->exit_on_time variable initialization has been added. The asignment of a value to the afl->afl_env.afl_exit_on_time variable from environment variables has been added. Code to exit on timeout if new path not found has been added. * Type of afl_exit_on_time variable has been changed. Variable exit_on_time has been added to the afl_state_t structure. * Command `export AFL_EXIT_WHEN_DONE=1` has been added. * Millisecond to second conversion has been added. Call get_cur_time() has been added. * Revert to using the saved current time value. * Useless check has been removed. * fix new path to custom-mutators * ensure crashes/README.txt exists * fix * Changes to bump FRIDA version and to clone FRIDA repo in to build directory rather than use a submodule as the FRIDA build scripts don't like it (#906) Co-authored-by: Your Name * Fix numeric overflow in cmplog implementation (#907) Co-authored-by: Your Name * testcase fixes for unicorn * remove merge conflict artifacts * fix afl-plot * Changes to remove binaries from frida_mode (#913) Co-authored-by: Your Name * Frida cmplog fail fast (#914) * Changes to remove binaries from frida_mode * Changes to make cmplog fail fast Co-authored-by: Your Name * afl-plot: relative time * arch linux and mac os support for afl-system-config * typo * code-format * update documentation * github workflow for qemu * OSX-specific improvements (#912) * Fix afl-cc to work correctly by default on OSX using xcode - CLANG_ENV_VAR must be set for afl-as to work - Use clang mode by default if no specific compiler selected * Add OSX-specific documentation for configuring shared memory * Fixes to memory operands for complog (#916) Co-authored-by: Your Name * fix a few cur_time uses * added bounds check to pivot_inputs (fixes #921) * additional safety checks for restarts * restrict afl-showmap in_file size * fix seed crash disable * add warning for afl-showmap partial read * no core dumps * AFL_PRINT_FILENAMES added * more documentation for AFL_EXIT_ON_TIME * Flushing for AFL_PRINT_FILENAMES * FASAN Support (#918) * FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name * Support for x86 (#920) Co-authored-by: Your Name * Update frida_mode readme (#925) * libqasan: use syscalls for read and write * update readme * Minor integration tweaks (#926) Co-authored-by: Your Name * merge * fix afl-fuzz.c frida preload * cleaned up AFL_PRINT_FILENAMES env * Changes to have persistent mode exit at the end of the loop (#928) Co-authored-by: Your Name * fix llvm-dict2file Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: hexcoder- Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza * improve error msg * Added documentation for wine LoadLibrary workaround (#933) * Fix cmake target compilation command example (#934) - Fix typo DCMAKE_C_COMPILERC -> DCMAKE_C_COMPILER. - Add `cd build` after `mkdir build`. * showmap passes queue items in alphabetical order * added tmp files to gitignore * lenient dict parsing, no map size enum for binary fuzzing * added info about showmap queue directions * update binary-only doc * turn off map size detection if skip_bin_check is set * Typo * update docs * update afl-system-config * Set kill signal before using it in afl-showmap (#935) * fix afl-cc help output * add libafl to binary-only doc * update docs * less executions on variable paths * AFL_SKIP_CRASHES is obsolete since 3.0 * add AFL_TRY_AFFINITY * Typo * Typo * Typo/wording * tweaks * typos * fix afl-whatsup help output * fix afl-plot output * fix for MacOS * fix cmpcov doc for qemu * fix tmpfile removal * update dockerfile * Frida (#940) * Added re2 test * Added libpcap test * Fix validation of setting of ADDR_NO_RANDOMIZE * Added support for printing original and instrumented code Co-authored-by: Your Name * Support for AFL_FRIDA_PERSISTENT_RET (#941) Co-authored-by: Your Name * Changes to add missing exclusion of ranges (#943) Co-authored-by: Your Name * add --afl-noopt to afl-cc * docs: fix link to README in QuickStartGuide (#946) * Support writing Stalker stats (#945) * Support writing Stalker stats * Fixed string handling in print functions Co-authored-by: Your Name * afl-cmin help fix, aflpp_driver - + @@ support * fix for afl-showmap * support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. * add documentation for AFL_LLVM_THREADSAFE_INST * add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes * add missing include for _exit() * threadsafe doc fixes, code format * Wording: "never zero" -> NeverZero * fix afl_custom_post_process with multiple custom mutators * fix docs * debug ck_write * fixed potential diff by 0 * fixes * fix classic threadsafe counters * v3.13c release Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: hexcoder- * v3.14a init * remove redundant unsetenv (#947) * update MacOS Install information * add missing clean action for frida_mode * ensure memory is there before free * adapt to incompatible LLVM 13 API * fix stupid typos * add fix info * build afl-compiler-rt even with broken llvm * fix -F with slash option * dynamic_list and afl-compiler-rt rework * detect partial linking in afl-cc * partial linking with -Wl * Add proper name and URL for Zafl (#959) * move link * add known frontends for supported compiler infrastructures * add Rust * fix ui fuzzing stage index (#960) * fix overflowing UI fields 'now processing' * restored timeout handling (with SIGALRM for now) * On non-Linux systems make clean may fail for frida_mode * give hint how to set env var for path to llvm-config tool * setting AFL_CC for test-llvm.sh on FreeBSD is not necessary anymore * remove -D from -M * write target errors to out_dir/error.txt * add changelog entry * add changelog * format * more info for error logging * Forkserver for afl-analyze (#963) * afl-analyze forkserver * added missing vars to forkserver * synchronized a bit more with afl-tmin * more debugging, runs now, but need to suppress target output * fix dev/null setting * afl-analyze info: Co-authored-by: hexcoder- * proper newlines * reenable LLVM 3.8 ( Ubuntu 16.04 ) * FRIDA AARCH64 support (#965) Co-authored-by: Your Name * adapt docs to minimum LLVM version * adapt to minimum llvm version * remove warning regarding core_pattern (was wrong/unnecessary anyway) * avoid code duplication, symlink header file * clippy fixes * add test cases for splitting integer comparisons * Revert "add test cases for splitting integer comparisons" This reverts commit e0aa411647e1a525a3a0488d929ec71611388d54. * add test cases for splitting integer comparisons * FRIDA - Remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET (#970) Co-authored-by: Your Name * fix AFL_CAL_FAST * fix cmplog screen update crash * Frida complog fix (#971) * Fix complog issue with changing address space * Added support for printing command line and environment during startup * Review fixes Co-authored-by: Your Name * Improve tracing support to include real addresses and edge ids and also support logging edges only once (#972) Co-authored-by: Your Name * split-comparison llvm pass refactor for smaller compilation times (and a small bug fix) (#964) * Refactored split compare pass to be more efficient in LTO usage and allow splitting to other minimum bitwidths. Efficiency: avoid looping over the whole llvm module N times, when once is also enough. Bitwidth: Previously, due to fallthrough in switch-case, all comparisons were split to 8-bit, which might not be desirable e.g., 16 or 32 bit might be enough. So now all comparison are split until they are smaller or equal to the target bitwidth, which is controlled through the `AFL_LLVM_LAF_SPLIT_COMPARES_BITW` environment variable. * fixed miscompilation due to incorrectly trying to split a signed comparison operator * minor formatting updates and use IRBuilder when inserting multiple instructions * added @hexcoder-'s test-int_cases.c to make test * Avoid recursion; switch to smallvector in splitAndSimplify; use switch case for icmp type; * Fixed issue when splitting < where the inverse comparison was not further split * some cleanup * code format * fix to instrument global c++ namespace functions * update changelog * document frida changes * Fix typo in README.md (#974) * adapt for LLVM 3.8.0 * fix README * little inline * Add debug output to alert user to calibration progress/issues (#969) * aflppdriver help output * code format Co-authored-by: hexcoder- Co-authored-by: Dominik Maier Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Co-authored-by: Your Name Co-authored-by: Dmitry Zheregelya Co-authored-by: hexcoder Co-authored-by: Andrea Fioraldi Co-authored-by: David CARLIER Co-authored-by: realmadsci <71108352+realmadsci@users.noreply.github.com> Co-authored-by: Roman M. Iudichev Co-authored-by: Dustin Spicuzza Co-authored-by: 0x4d5a-ctf <51098072+0x4d5a-ctf@users.noreply.github.com> Co-authored-by: Tommy Chiang Co-authored-by: buherator Co-authored-by: Dag Heyman Kajevic Co-authored-by: terrynini Co-authored-by: jdhiser Co-authored-by: yuan Co-authored-by: Michael Rodler Co-authored-by: Artis <32833063+Artis24106@users.noreply.github.com> --- README.md | 30 +- custom_mutators/radamsa/custom_mutator_helpers.h | 343 +------- docs/Changelog.md | 27 +- docs/FAQ.md | 21 + docs/env_variables.md | 4 +- frida_mode/GNUmakefile | 1 + frida_mode/README.md | 10 +- frida_mode/src/cmplog/cmplog.c | 84 ++ frida_mode/src/instrument/instrument.c | 111 ++- frida_mode/src/main.c | 84 +- frida_mode/src/persistent/persistent.c | 13 - frida_mode/src/persistent/persistent_arm64.c | 12 +- frida_mode/src/persistent/persistent_x64.c | 53 +- frida_mode/src/persistent/persistent_x86.c | 40 +- frida_mode/test/persistent_ret/GNUmakefile | 5 - frida_mode/test/unstable/GNUmakefile | 90 +++ frida_mode/test/unstable/Makefile | 19 + frida_mode/test/unstable/get_symbol_addr.py | 36 + frida_mode/test/unstable/unstable.c | 67 ++ include/afl-fuzz.h | 4 +- include/envs.h | 2 +- instrumentation/afl-llvm-common.cc | 5 +- instrumentation/split-compares-pass.so.cc | 985 ++++++++++++----------- src/afl-analyze.c | 9 +- src/afl-common.c | 2 + src/afl-fuzz-one.c | 2 +- src/afl-fuzz-redqueen.c | 91 ++- src/afl-fuzz-run.c | 26 +- src/afl-fuzz-state.c | 9 +- src/afl-fuzz.c | 9 - test/test-basic.sh | 10 - test/test-gcc-plugin.sh | 4 - test/test-int_cases.c | 424 ++++++++++ test/test-llvm.sh | 27 +- test/test-uint_cases.c | 217 +++++ unicorn_mode/samples/speedtest/rust/src/main.rs | 11 +- utils/aflpp_driver/aflpp_driver.c | 32 +- 37 files changed, 1922 insertions(+), 997 deletions(-) mode change 100644 => 120000 custom_mutators/radamsa/custom_mutator_helpers.h create mode 100644 frida_mode/test/unstable/GNUmakefile create mode 100644 frida_mode/test/unstable/Makefile create mode 100755 frida_mode/test/unstable/get_symbol_addr.py create mode 100644 frida_mode/test/unstable/unstable.c create mode 100644 test/test-int_cases.c create mode 100644 test/test-uint_cases.c (limited to 'docs') diff --git a/README.md b/README.md index bc547b3c..91f28118 100644 --- a/README.md +++ b/README.md @@ -88,20 +88,20 @@ behaviours and defaults: with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. - | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | - | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| - | Threadsafe counters | | x(3) | | | | | - | NeverZero | x86[_64]| x(1) | x | x | x | x | - | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | - | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | x86[_64] | x86[_64]/arm[64] | | - | Selective Instrumentation| | x | x | x | x | | - | Non-Colliding Coverage | | x(4) | | | (x)(5) | | - | Ngram prev_loc Coverage | | x(6) | | | | | - | Context Coverage | | x(6) | | | | | - | Auto Dictionary | | x(7) | | | | | - | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | - | Shared Memory Testcases | | x | x | x | x | x | + | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | + | -------------------------|:-------:|:---------:|:----------:|:----------------:|:----------------:|:----------------:| + | Threadsafe counters | | x(3) | | | | | + | NeverZero | x86[_64]| x(1) | x | x | x | x | + | Persistent Mode | | x | x | x86[_64]/arm64 | x86[_64]/arm[64] | x | + | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | + | CmpLog | | x | | x86[_64]/arm64 | x86[_64]/arm[64] | | + | Selective Instrumentation| | x | x | x | x | | + | Non-Colliding Coverage | | x(4) | | | (x)(5) | | + | Ngram prev_loc Coverage | | x(6) | | | | | + | Context Coverage | | x(6) | | | | | + | Auto Dictionary | | x(7) | | | | | + | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | + | Shared Memory Testcases | | x | x | x86[_64]/arm64 | x | x | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin @@ -796,7 +796,7 @@ If you do not have to use Unicorn the following setup is recommended to use qemu_mode: * run 1 afl-fuzz -Q instance with CMPLOG (`-c 0` + `AFL_COMPCOV_LEVEL=2`) * run 1 afl-fuzz -Q instance with QASAN (`AFL_USE_QASAN=1`) - * run 1 afl-fuzz -Q instance with LAF (``AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`) + * run 1 afl-fuzz -Q instance with LAF (`AFL_PRELOAD=libcmpcov.so` + `AFL_COMPCOV_LEVEL=2`) Alternatively you can use frida_mode, just switch `-Q` with `-O` and remove the LAF instance. diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h deleted file mode 100644 index e23c0b6a..00000000 --- a/custom_mutators/radamsa/custom_mutator_helpers.h +++ /dev/null @@ -1,342 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include - -#define INITIAL_GROWTH_SIZE (64) - -#define RAND_BELOW(limit) (rand() % (limit)) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this filles in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -typedef struct { - -} afl_t; - -static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) { - - static s8 interesting_8[] = {INTERESTING_8}; - static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; - static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - - switch (RAND_BELOW(12)) { - - case 0: { - - /* Flip a single bit somewhere. Spooky! */ - - s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8); - - out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7); - - break; - - } - - case 1: { - - /* Set byte to interesting value. */ - - u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))]; - out_buf[(RAND_BELOW(end - begin) + begin)] = val; - - break; - - } - - case 2: { - - /* Set word to interesting value, randomly choosing endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u16 *)(out_buf + byte_idx) = - interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]; - break; - case 1: - *(u16 *)(out_buf + byte_idx) = - SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]); - break; - - } - - break; - - } - - case 3: { - - /* Set dword to interesting value, randomly choosing endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u32 *)(out_buf + byte_idx) = - interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u32 *)(out_buf + byte_idx) = - SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 4: { - - /* Set qword to interesting value, randomly choosing endian. */ - - if (end - begin < 8) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 7) break; - - switch (RAND_BELOW(2)) { - - case 0: - *(u64 *)(out_buf + byte_idx) = - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]; - break; - case 1: - *(u64 *)(out_buf + byte_idx) = SWAP64( - (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]); - break; - - } - - break; - - } - - case 5: { - - /* Randomly subtract from byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 6: { - - /* Randomly add to byte. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX); - - break; - - } - - case 7: { - - /* Randomly subtract from word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 8: { - - /* Randomly add to word, random endian. */ - - if (end - begin < 2) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 1) break; - - if (RAND_BELOW(2)) { - - *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u16 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u16 *)(out_buf + byte_idx) = - SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 9: { - - /* Randomly subtract from dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num); - - } - - break; - - } - - case 10: { - - /* Randomly add to dword, random endian. */ - - if (end - begin < 4) break; - - s32 byte_idx = (RAND_BELOW(end - begin) + begin); - - if (byte_idx >= end - 3) break; - - if (RAND_BELOW(2)) { - - *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX); - - } else { - - u32 num = 1 + RAND_BELOW(ARITH_MAX); - - *(u32 *)(out_buf + byte_idx) = - SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num); - - } - - break; - - } - - case 11: { - - /* Just set a random byte to a random value. Because, - why not. We use XOR with 1-255 to eliminate the - possibility of a no-op. */ - - out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255); - - break; - - } - - } - -} - -/* This function calculates the next power of 2 greater or equal its argument. - @return The rounded up power of 2 (if no overflow) or 0 on overflow. -*/ -static inline size_t next_pow2(size_t in) { - - if (in == 0 || in > (size_t)-1) - return 0; /* avoid undefined behaviour under-/overflow */ - size_t out = in - 1; - out |= out >> 1; - out |= out >> 2; - out |= out >> 4; - out |= out >> 8; - out |= out >> 16; - return out + 1; - -} - -/* This function makes sure *size is > size_needed after call. - It will realloc *buf otherwise. - *size will grow exponentially as per: - https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/ - Will return NULL and free *buf if size_needed is <1 or realloc failed. - @return For convenience, this function returns *buf. - */ -static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) { - - /* No need to realloc */ - if (likely(size_needed && *size >= size_needed)) return *buf; - - /* No initial size was set */ - if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE; - - /* grow exponentially */ - size_t next_size = next_pow2(size_needed); - - /* handle overflow */ - if (!next_size) { next_size = size_needed; } - - /* alloc */ - *buf = realloc(*buf, next_size); - *size = *buf ? next_size : 0; - - return *buf; - -} - -/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */ -static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2, - size_t *size2) { - - void * scratch_buf = *buf1; - size_t scratch_size = *size1; - *buf1 = *buf2; - *size1 = *size2; - *buf2 = scratch_buf; - *size2 = scratch_size; - -} - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h new file mode 120000 index 00000000..f7532ef9 --- /dev/null +++ b/custom_mutators/radamsa/custom_mutator_helpers.h @@ -0,0 +1 @@ +../examples/custom_mutator_helpers.h \ No newline at end of file diff --git a/docs/Changelog.md b/docs/Changelog.md index 6c851460..9f70535a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,20 +9,29 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.14a (release) - - Fix for llvm 13 - afl-fuzz: - fix -F when a '/' was part of the parameter + - fixed a crash for cmplog for very slow inputs - removed implied -D determinstic from -M main - - if the target becomes unavailable check out out/default/error.txt for - an indicator why - - afl-cc + - if the target becomes unavailable check out out/default/error.txt + for an indicator why + - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL + - afl-cc: + - Update to COMPCOV/laf-intel that speeds up the instrumentation + process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix to instrument global namespace functions in c++ + - Fix for llvm 13 - support partial linking - - We do support llvm versions from 3.8 again - - afl_analyze - - fix timeout handling and support forkserver + - We do support llvm versions from 3.8 to 5.0 again + - frida_mode: + - fix for cmplog + - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - feature parity of aarch64 with intel now (persistent, cmplog, + in-memory testcases, asan) + - afl_analyze: + - fix timeout handling + - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module - - afl-analyze now uses the forkserver for increased performance - ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 diff --git a/docs/FAQ.md b/docs/FAQ.md index 714d50eb..ab0abe6c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -3,6 +3,7 @@ ## Contents * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) + * [I got a weird compile error from clang](#i-got-a-weird-compile-error-from-clang) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) @@ -35,6 +36,26 @@ flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) +## I got a weird compile error from clang + +If you see this kind of error when trying to instrument a target with afl-cc/ +afl-clang-fast/afl-clang-lto: +``` +/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv +clang-13: error: unable to execute command: No such file or directory +clang-13: error: clang frontend command failed due to signal (use -v to see invocation) +clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad) +Target: x86_64-unknown-linux-gnu +Thread model: posix +InstalledDir: /prg/tmp/llvm-project/build/bin +clang-13: note: diagnostic msg: +******************** +``` +Then this means that your OS updated the clang installation from an upgrade +package and because of that the afl++ llvm plugins do not match anymore. + +Solution: `git pull ; make clean install` of afl++ + ## How to improve the fuzzing speed? 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) diff --git a/docs/env_variables.md b/docs/env_variables.md index 38a67bc7..e058f377 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -108,9 +108,6 @@ make fairly broad use of environmental variables instead: - Setting `AFL_QUIET` will prevent afl-cc and afl-as banners from being displayed during compilation, in case you find them distracting. - - Setting `AFL_CAL_FAST` will speed up the initial calibration, if the - application is very slow. - ## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset @@ -386,6 +383,7 @@ checks or alter some of the more exotic semantics of the tool: - `AFL_FAST_CAL` keeps the calibration stage about 2.5x faster (albeit less precise), which can help when starting a session against a slow target. + `AFL_CAL_FAST` works too. - The CPU widget shown at the bottom of the screen is fairly simplistic and may complain of high load prematurely, especially on systems with low core diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index a0387cac..329d9f7f 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -20,6 +20,7 @@ RT_CFLAGS:=-Wno-unused-parameter \ -Wno-unused-function \ -Wno-unused-result \ -Wno-int-to-pointer-cast \ + -Wno-pointer-sign \ LDFLAGS+=-shared \ -lpthread \ diff --git a/frida_mode/README.md b/frida_mode/README.md index d7dd72a0..296e6405 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -75,7 +75,6 @@ following options are currently supported: * `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` * `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` * `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET` -* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET` To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`. @@ -156,16 +155,17 @@ instrumentation (the default where available). Required to use * `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will report instrumented blocks back to the parent so that it can also instrument them and they be inherited by the next child on fork. -* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks -`AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks, +requires `AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_INST_TRACE_UNIQUE` - As per `AFL_FRIDA_INST_TRACE`, but each edge +is logged only once, requires `AFL_FRIDA_INST_NO_OPTIMIZE`. * `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) * `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) * `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user -to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a -debugger. +to detect issues in the persistent loop using a debugger. ``` diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 7b11c350..3df7d13d 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -1,3 +1,8 @@ +#include +#include +#include +#include + #include "frida-gum.h" #include "debug.h" @@ -5,10 +10,13 @@ #include "util.h" #define DEFAULT_MMAP_MIN_ADDR (32UL << 10) +#define FD_TMP_MAX_SIZE 65536 extern struct cmp_map *__afl_cmp_map; static GArray *cmplog_ranges = NULL; +static int fd_tmp = -1; +static ssize_t fd_tmp_size = 0; static gboolean cmplog_range(const GumRangeDetails *details, gpointer user_data) { @@ -27,6 +35,40 @@ static gint cmplog_sort(gconstpointer a, gconstpointer b) { } +static int cmplog_create_temp(void) { + + const char *tmpdir = g_get_tmp_dir(); + OKF("CMPLOG Temporary directory: %s", tmpdir); + gchar *fname = g_strdup_printf("%s/frida-cmplog-XXXXXX", tmpdir); + OKF("CMPLOG Temporary file template: %s", fname); + int fd = mkstemp(fname); + OKF("CMPLOG Temporary file: %s", fname); + + if (fd < 0) { + + FATAL("Failed to create temp file: %s, errno: %d", fname, errno); + + } + + if (unlink(fname) < 0) { + + FATAL("Failed to unlink temp file: %s (%d), errno: %d", fname, fd, errno); + + } + + if (ftruncate(fd, 0) < 0) { + + FATAL("Failed to ftruncate temp file: %s (%d), errno: %d", fname, fd, + errno); + + } + + g_free(fname); + + return fd; + +} + void cmplog_init(void) { if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } @@ -44,6 +86,13 @@ void cmplog_init(void) { } + /* + * We can't use /dev/null or /dev/zero for this since it appears that they + * don't validate the input buffer. Persumably as an optimization because they + * don't actually write any data. The file will be deleted on close. + */ + fd_tmp = cmplog_create_temp(); + } static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, @@ -67,6 +116,9 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) { */ if (addr < DEFAULT_MMAP_MIN_ADDR) { return false; } + /* Check our addres/length don't wrap around */ + if (SIZE_MAX - addr < size) { return false; } + GumAddress inner_base = addr; GumAddress inner_limit = inner_base + size; @@ -81,6 +133,38 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) { } + /* + * Our address map can change (e.g. stack growth), use write as a fallback to + * validate our address. + */ + ssize_t written = syscall(__NR_write, fd_tmp, (void *)addr, size); + + /* + * If the write succeeds, then the buffer must be valid otherwise it would + * return EFAULT + */ + if (written > 0) { + + fd_tmp_size += written; + if (fd_tmp_size > FD_TMP_MAX_SIZE) { + + /* + * Truncate the file, we don't want our temp file to continue growing! + */ + if (ftruncate(fd_tmp, 0) < 0) { + + FATAL("Failed to truncate fd_tmp (%d), errno: %d", fd_tmp, errno); + + } + + fd_tmp_size = 0; + + } + + if ((size_t)written == size) { return true; } + + } + return false; } diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index f261e79a..ba82b89f 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -1,4 +1,6 @@ #include +#include +#include #include "frida-gum.h" @@ -18,44 +20,50 @@ static gboolean tracing = false; static gboolean optimize = false; +static gboolean unique = false; static GumStalkerTransformer *transformer = NULL; __thread uint64_t previous_pc = 0; +static GumAddress previous_rip = 0; +static u8 * edges_notified = NULL; + +static void trace_debug(char *format, ...) { + + va_list ap; + char buffer[4096] = {0}; + int ret; + int len; + + va_start(ap, format); + ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); + va_end(ap); + + if (ret < 0) { return; } + + len = strnlen(buffer, sizeof(buffer)); + + IGNORED_RETURN(write(STDOUT_FILENO, buffer, len)); + +} + __attribute__((hot)) static void on_basic_block(GumCpuContext *context, gpointer user_data) { UNUSED_PARAMETER(context); - /* - * This function is performance critical as it is called to instrument every - * basic block. By moving our print buffer to a global, we avoid it affecting - * the critical path with additional stack adjustments if tracing is not - * enabled. If tracing is enabled, then we're printing a load of diagnostic - * information so this overhead is unlikely to be noticeable. - */ - static char buffer[200]; - int len; - GumAddress current_pc = GUM_ADDRESS(user_data); - uint8_t * cursor; - uint64_t value; - if (unlikely(tracing)) { - - /* Avoid any functions which may cause an allocation since the target app - * may already be running inside malloc and it isn't designed to be - * re-entrant on a single thread */ - len = snprintf(buffer, sizeof(buffer), - "current_pc: 0x%016" G_GINT64_MODIFIER - "x, previous_pc: 0x%016" G_GINT64_MODIFIER "x\n", - current_pc, previous_pc); - IGNORED_RETURN(write(STDOUT_FILENO, buffer, len + 1)); + GumAddress current_rip = GUM_ADDRESS(user_data); + GumAddress current_pc; + GumAddress edge; + uint8_t * cursor; + uint64_t value; - } - - current_pc = (current_pc >> 4) ^ (current_pc << 8); + current_pc = (current_rip >> 4) ^ (current_rip << 8); current_pc &= MAP_SIZE - 1; - cursor = &__afl_area_ptr[current_pc ^ previous_pc]; + edge = current_pc ^ previous_pc; + + cursor = &__afl_area_ptr[edge]; value = *cursor; if (value == 0xff) { @@ -71,6 +79,23 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, *cursor = value; previous_pc = current_pc >> 1; + if (unlikely(tracing)) { + + if (!unique || edges_notified[edge] == 0) { + + trace_debug("TRACE: edge: %10" G_GINT64_MODIFIER + "d, current_rip: 0x%016" G_GINT64_MODIFIER + "x, previous_rip: 0x%016" G_GINT64_MODIFIER "x\n", + edge, current_rip, previous_rip); + + } + + if (unique) { edges_notified[edge] = 1; } + + previous_rip = current_rip; + + } + } static void instr_basic_block(GumStalkerIterator *iterator, @@ -164,18 +189,28 @@ void instrument_init(void) { optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); + unique = (getenv("AFL_FRIDA_INST_TRACE_UNIQUE") != NULL); if (!instrument_is_coverage_optimize_supported()) optimize = false; OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); + OKF("Instrumentation - unique [%c]", unique ? 'X' : ' '); if (tracing && optimize) { - FATAL("AFL_FRIDA_INST_OPTIMIZE and AFL_FRIDA_INST_TRACE are incompatible"); + FATAL("AFL_FRIDA_INST_TRACE requires AFL_FRIDA_INST_NO_OPTIMIZE"); + + } + + if (unique && optimize) { + + FATAL("AFL_FRIDA_INST_TRACE_UNIQUE requires AFL_FRIDA_INST_NO_OPTIMIZE"); } + if (unique) { tracing = TRUE; } + if (__afl_map_size != 0x10000) { FATAL("Bad map size: 0x%08x", __afl_map_size); @@ -185,6 +220,28 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + if (unique) { + + int shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600); + if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } + + edges_notified = shmat(shm_id, NULL, 0); + g_assert(edges_notified != MAP_FAILED); + + /* + * Configure the shared memory region to be removed once the process dies. + */ + if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + + FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); + + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(edges_notified, '\0', MAP_SIZE); + + } + instrument_debug_init(); asan_init(); cmplog_init(); diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 1ab9993f..7ff23755 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -27,6 +28,8 @@ #include "stats.h" #include "util.h" +#define PROC_MAX 65536 + #ifdef __APPLE__ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); @@ -78,7 +81,7 @@ static void on_main_os(int argc, char **argv, char **envp) { #endif -static void embedded_init() { +static void embedded_init(void) { static gboolean initialized = false; if (!initialized) { @@ -90,7 +93,84 @@ static void embedded_init() { } -void afl_frida_start() { +static void afl_print_cmdline(void) { + + char * buffer = g_malloc0(PROC_MAX); + gchar *fname = g_strdup_printf("/proc/%d/cmdline", getppid()); + int fd = open(fname, O_RDONLY); + + if (fd < 0) { + + FATAL("Failed to open /proc/self/cmdline, errno: (%d)", errno); + + } + + ssize_t bytes_read = read(fd, buffer, PROC_MAX - 1); + if (bytes_read < 0) { + + FATAL("Failed to read /proc/self/cmdline, errno: (%d)", errno); + + } + + int idx = 0; + + for (ssize_t i = 0; i < bytes_read; i++) { + + if (i == 0 || buffer[i - 1] == '\0') { + + OKF("AFL - COMMANDLINE: argv[%d] = %s", idx++, &buffer[i]); + + } + + } + + close(fd); + g_free(fname); + g_free(buffer); + +} + +static void afl_print_env(void) { + + char * buffer = g_malloc0(PROC_MAX); + gchar *fname = g_strdup_printf("/proc/%d/environ", getppid()); + int fd = open(fname, O_RDONLY); + + if (fd < 0) { + + FATAL("Failed to open /proc/self/cmdline, errno: (%d)", errno); + + } + + ssize_t bytes_read = read(fd, buffer, PROC_MAX - 1); + if (bytes_read < 0) { + + FATAL("Failed to read /proc/self/cmdline, errno: (%d)", errno); + + } + + int idx = 0; + + for (ssize_t i = 0; i < bytes_read; i++) { + + if (i == 0 || buffer[i - 1] == '\0') { + + OKF("AFL - ENVIRONMENT %3d: %s", idx++, &buffer[i]); + + } + + } + + close(fd); + g_free(fname); + g_free(buffer); + +} + +void afl_frida_start(void) { + + afl_print_cmdline(); + afl_print_env(); embedded_init(); stalker_init(); diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index 2ec5b9cc..243d501d 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -13,7 +13,6 @@ afl_persistent_hook_fn hook = NULL; guint64 persistent_start = 0; guint64 persistent_count = 0; guint64 persistent_ret = 0; -guint64 persistent_ret_offset = 0; gboolean persistent_debug = FALSE; void persistent_init(void) { @@ -23,8 +22,6 @@ void persistent_init(void) { persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET"); - persistent_ret_offset = - util_read_address("AFL_FRIDA_PERSISTENT_RETADDR_OFFSET"); if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; } @@ -44,14 +41,6 @@ void persistent_init(void) { } - if (persistent_ret_offset != 0 && persistent_ret == 0) { - - FATAL( - "AFL_FRIDA_PERSISTENT_RET must be specified if " - "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET is"); - - } - if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; if (persistent_count != 0 && persistent_count < 100) @@ -68,8 +57,6 @@ void persistent_init(void) { OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", persistent_ret == 0 ? ' ' : 'X', persistent_ret); - OKF("Instrumentation - persistent ret offset [%c] (%" G_GINT64_MODIFIER "d)", - persistent_ret_offset == 0 ? ' ' : 'X', persistent_ret_offset); if (hook_name != NULL) { diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c index b23693fe..d7c6c76b 100644 --- a/frida_mode/src/persistent/persistent_arm64.c +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -268,13 +268,15 @@ static void instrument_persitent_restore_regs(GumArm64Writer * cw, ARM64_REG_X0, (16 * 14), GUM_INDEX_SIGNED_OFFSET); - /* Don't restore RIP or RSP, use x1-x3 as clobber */ - - /* LR & Adjusted SP (clobber x1) */ + /* LR & Adjusted SP (use x1 as clobber) */ gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X1, ARM64_REG_X0, (16 * 15), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_SP, ARM64_REG_X1); + + /* Don't restore RIP use x1-x3 as clobber */ + /* PC (x2) & CPSR (x1) */ gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1, ARM64_REG_X0, (16 * 16), @@ -404,7 +406,6 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; - /* Stack must be 16-byte aligned per ABI */ instrument_persitent_save_regs(cw, &saved_regs); /* loop: */ @@ -450,9 +451,6 @@ void persistent_epilogue(GumStalkerOutput *output) { if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); } - gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, - persistent_ret_offset); - gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0, GUM_ADDRESS(&saved_lr)); diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index 858ad38e..653acefe 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -43,6 +43,7 @@ struct x86_64_regs { typedef struct x86_64_regs arch_api_regs; static arch_api_regs saved_regs = {0}; +static gpointer saved_ret = NULL; gboolean persistent_is_supported(void) { @@ -104,7 +105,7 @@ static void instrument_persitent_save_regs(GumX86Writer * cw, /* RED_ZONE + Saved flags, RAX, alignment */ gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX, - GUM_RED_ZONE_SIZE + (0x8 * 3)); + GUM_RED_ZONE_SIZE + (0x8 * 2)); gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16), GUM_REG_RBX); @@ -159,7 +160,9 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw, gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX, (0x8 * 14)); - /* Don't restore RIP or RSP */ + /* Don't restore RIP */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSP, GUM_REG_RAX, + (0x8 * 16)); /* Restore RBX, RAX & Flags */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, @@ -242,6 +245,31 @@ static void persistent_prologue_hook(GumX86Writer * cw, } +static void instrument_persitent_save_ret(GumX86Writer *cw) { + + /* Stack usage by this function */ + gssize offset = GUM_RED_ZONE_SIZE + (3 * 8); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + -(GUM_RED_ZONE_SIZE)); + + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, + offset); + gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_RAX, GUM_REG_RBX); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX); + gum_x86_writer_put_popfx(cw); + + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, + (GUM_RED_ZONE_SIZE)); + +} + void persistent_prologue(GumStalkerOutput *output) { /* @@ -268,11 +296,10 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; - /* Stack must be 16-byte aligned per ABI */ - instrument_persitent_save_regs(cw, &saved_regs); + /* Pop the return value */ + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 8); - /* pop the return value */ - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8)); + instrument_persitent_save_regs(cw, &saved_regs); /* loop: */ gum_x86_writer_put_label(cw, loop); @@ -304,6 +331,8 @@ void persistent_prologue(GumStalkerOutput *output) { /* original: */ gum_x86_writer_put_label(cw, original); + instrument_persitent_save_ret(cw); + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } } @@ -314,9 +343,15 @@ void persistent_epilogue(GumStalkerOutput *output) { if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - persistent_ret_offset); - gum_x86_writer_put_ret(cw); + /* The stack should be aligned when we re-enter our loop */ + gconstpointer zero = cw->code + 1; + gum_x86_writer_put_test_reg_u32(cw, GUM_REG_RSP, 0xF); + gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, zero, GUM_NO_HINT); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -8); + gum_x86_writer_put_label(cw, zero); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret)); + gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_RAX); } diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 0675edf4..7add6e99 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -39,6 +39,7 @@ struct x86_regs { typedef struct x86_regs arch_api_regs; static arch_api_regs saved_regs = {0}; +static gpointer saved_ret = NULL; gboolean persistent_is_supported(void) { @@ -117,7 +118,9 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw, gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX, (0x4 * 6)); - /* Don't restore RIP or RSP */ + /* Don't restore RIP */ + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX, + (0x4 * 8)); /* Restore RBX, RAX & Flags */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, @@ -184,6 +187,26 @@ static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { } +static void instrument_persitent_save_ret(GumX86Writer *cw) { + + /* Stack usage by this function */ + gssize offset = (3 * 4); + + gum_x86_writer_put_pushfx(cw); + gum_x86_writer_put_push_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); + + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret)); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, + offset); + gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_EAX, GUM_REG_EBX); + + gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX); + gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX); + gum_x86_writer_put_popfx(cw); + +} + void persistent_prologue(GumStalkerOutput *output) { /* @@ -210,11 +233,10 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; - /* Stack must be 16-byte aligned per ABI */ - instrument_persitent_save_regs(cw, &saved_regs); - /* Pop the return value */ - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4)); + gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4); + + instrument_persitent_save_regs(cw, &saved_regs); /* loop: */ gum_x86_writer_put_label(cw, loop); @@ -244,6 +266,8 @@ void persistent_prologue(GumStalkerOutput *output) { /* original: */ gum_x86_writer_put_label(cw, original); + instrument_persitent_save_ret(cw); + if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } } @@ -254,10 +278,8 @@ void persistent_epilogue(GumStalkerOutput *output) { if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); } - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, - persistent_ret_offset); - - gum_x86_writer_put_ret(cw); + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret)); + gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_EAX); } diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index 4c9d8a19..2de51d86 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -38,8 +38,6 @@ ifeq "$(ARCH)" "x86" AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000) endif -AFL_FRIDA_PERSISTENT_RETADDR_OFFSET:=0x50 - .PHONY: all 32 clean qemu frida all: $(TESTINSTBIN) @@ -76,7 +74,6 @@ frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ - AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ $(ROOT)afl-fuzz \ -D \ -O \ @@ -89,7 +86,6 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) gdb \ --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ --ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \ - --ex 'set environment AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET)' \ --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ --ex 'set environment AFL_DEBUG_CHILD=1' \ --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ @@ -99,7 +95,6 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) run: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ - AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \ AFL_DEBUG_CHILD=1 \ LD_PRELOAD=$(ROOT)afl-frida-trace.so \ $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) diff --git a/frida_mode/test/unstable/GNUmakefile b/frida_mode/test/unstable/GNUmakefile new file mode 100644 index 00000000..fed417a3 --- /dev/null +++ b/frida_mode/test/unstable/GNUmakefile @@ -0,0 +1,90 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +UNSTABLE_DATA_DIR:=$(BUILD_DIR)in/ +UNSTABLE_DATA_FILE:=$(UNSTABLE_DATA_DIR)in + +UNSTABLE_BIN:=$(BUILD_DIR)unstable +UNSTABLE_SRC:=$(PWD)unstable.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x4000000000) + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x56555000) +endif + +.PHONY: all 32 clean qemu frida + +all: $(UNSTABLE_BIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(UNSTABLE_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(UNSTABLE_DATA_FILE): | $(UNSTABLE_DATA_DIR) + echo -n "000" > $@ + +$(UNSTABLE_BIN): $(UNSTABLE_SRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + + +qemu: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -Q \ + -i $(UNSTABLE_DATA_DIR) \ + -o $(QEMU_OUT) \ + -- \ + $(UNSTABLE_BIN) @@ + +frida: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) + AFL_DEBUG=1 \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_INST_TRACE_UNIQUE=1 \ + AFL_FRIDA_INST_NO_OPTIMIZE=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(UNSTABLE_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(UNSTABLE_BIN) @@ + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) diff --git a/frida_mode/test/unstable/Makefile b/frida_mode/test/unstable/Makefile new file mode 100644 index 00000000..f843af19 --- /dev/null +++ b/frida_mode/test/unstable/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +debug: + @gmake debug diff --git a/frida_mode/test/unstable/get_symbol_addr.py b/frida_mode/test/unstable/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/unstable/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/unstable/unstable.c b/frida_mode/test/unstable/unstable.c new file mode 100644 index 00000000..67d56b73 --- /dev/null +++ b/frida_mode/test/unstable/unstable.c @@ -0,0 +1,67 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include + +#ifdef __APPLE__ + #define TESTINSTR_SECTION +#else + #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) +#endif + +void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + + if (size < 1) return; + + int r = rand(); + if ((r % 2) == 0) { + printf ("Hooray all even\n"); + } else { + printf ("Hmm that's odd\n"); + } + + // we support three input cases + if (data[0] == '0') + printf("Looks like a zero to me!\n"); + else if (data[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +void run_test(char * file) { + fprintf(stderr, "Running: %s\n", file); + FILE *f = fopen(file, "r"); + assert(f); + fseek(f, 0, SEEK_END); + size_t len = ftell(f); + fseek(f, 0, SEEK_SET); + unsigned char *buf = (unsigned char*)malloc(len); + size_t n_read = fread(buf, 1, len, f); + fclose(f); + assert(n_read == len); + LLVMFuzzerTestOneInput(buf, len); + free(buf); + fprintf(stderr, "Done: %s: (%zd bytes)\n", file, n_read); +} + +int main(int argc, char **argv) { + srand(1); + fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); + for (int i = 1; i < argc; i++) { + run_test(argv[i]); + } +} diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4aba3bdf..2920f905 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -478,9 +478,7 @@ typedef struct afl_state { u32 hang_tmout; /* Timeout used for hang det (ms) */ - u8 cal_cycles, /* Calibration cycles defaults */ - cal_cycles_long, /* Calibration cycles defaults */ - havoc_stack_pow2, /* HAVOC_STACK_POW2 */ + u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */ no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ diff --git a/include/envs.h b/include/envs.h index 15116fc1..54bb6597 100644 --- a/include/envs.h +++ b/include/envs.h @@ -60,6 +60,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_TRACE", + "AFL_FRIDA_INST_UNSTABLE", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR", "AFL_FRIDA_PERSISTENT_ADDR", @@ -67,7 +68,6 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_PERSISTENT_DEBUG", "AFL_FRIDA_PERSISTENT_HOOK", "AFL_FRIDA_PERSISTENT_RET", - "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET", "AFL_FRIDA_STATS_FILE", "AFL_FRIDA_STATS_INTERVAL", "AFL_FRIDA_STATS_TRANSITIONS", diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index af32e2f9..3239ea91 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -96,9 +96,8 @@ bool isIgnoreFunction(const llvm::Function *F) { static constexpr const char *ignoreSubstringList[] = { - "__asan", "__msan", "__ubsan", "__lsan", - "__san", "__sanitize", "__cxx", "_GLOBAL__", - "DebugCounter", "DwarfDebug", "DebugLoc" + "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize", + "__cxx", "DebugCounter", "DwarfDebug", "DebugLoc" }; diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index b02a89fb..68f6c329 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -47,6 +47,10 @@ using namespace llvm; #include "afl-llvm-common.h" +// uncomment this toggle function verification at each step. horribly slow, but +// helps to pinpoint a potential problem in the splitting code. +//#define VERIFY_TOO_MUCH 1 + namespace { class SplitComparesTransform : public ModulePass { @@ -67,28 +71,101 @@ class SplitComparesTransform : public ModulePass { const char *getPassName() const override { #endif - return "simplifies and splits ICMP instructions"; + return "AFL_SplitComparesTransform"; } private: int enableFPSplit; - size_t splitIntCompares(Module &M, unsigned bitw); + unsigned target_bitwidth = 8; + + size_t count = 0; + size_t splitFPCompares(Module &M); - bool simplifyCompares(Module &M); bool simplifyFPCompares(Module &M); - bool simplifyIntSignedness(Module &M); size_t nextPowerOfTwo(size_t in); + using CmpWorklist = SmallVector; + + /// simplify the comparison and then split the comparison until the + /// target_bitwidth is reached. + bool simplifyAndSplit(CmpInst *I, Module &M); + /// simplify a non-strict comparison (e.g., less than or equals) + bool simplifyOrEqualsCompare(CmpInst *IcmpInst, Module &M, + CmpWorklist &worklist); + /// simplify a signed comparison (signed less or greater than) + bool simplifySignedCompare(CmpInst *IcmpInst, Module &M, + CmpWorklist &worklist); + /// splits an icmp into nested icmps recursivly until target_bitwidth is + /// reached + bool splitCompare(CmpInst *I, Module &M, CmpWorklist &worklist); + + /// print an error to llvm's errs stream, but only if not ordered to be quiet + void reportError(const StringRef msg, Instruction *I, Module &M) { + + if (!be_quiet) { + + errs() << "[AFL++ SplitComparesTransform] ERROR: " << msg << "\n"; + if (debug) { + + if (I) { + + errs() << "Instruction = " << *I << "\n"; + if (auto BB = I->getParent()) { + + if (auto F = BB->getParent()) { + + if (F->hasName()) { + + errs() << "|-> in function " << F->getName() << " "; + + } + + } + + } + + } + + auto n = M.getName(); + if (n.size() > 0) { errs() << "in module " << n << "\n"; } + + } + + } + + } + + bool isSupportedBitWidth(unsigned bitw) { + + // IDK whether the icmp code works on other bitwidths. I guess not? So we + // try to avoid dealing with other weird icmp's that llvm might use (looking + // at you `icmp i0`). + switch (bitw) { + + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + return true; + default: + return false; + + } + + } + }; } // namespace char SplitComparesTransform::ID = 0; -/* This function splits FCMP instructions with xGE or xLE predicates into two - * FCMP instructions with predicate xGT or xLT and EQ */ +/// This function splits FCMP instructions with xGE or xLE predicates into two +/// FCMP instructions with predicate xGT or xLT and EQ bool SplitComparesTransform::simplifyFPCompares(Module &M) { LLVMContext & C = M.getContext(); @@ -221,292 +298,481 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { } -/* This function splits ICMP instructions with xGE or xLE predicates into two - * ICMP instructions with predicate xGT or xLT and EQ */ -bool SplitComparesTransform::simplifyCompares(Module &M) { +/// This function splits ICMP instructions with xGE or xLE predicates into two +/// ICMP instructions with predicate xGT or xLT and EQ +bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, + Module & M, + CmpWorklist &worklist) { - LLVMContext & C = M.getContext(); - std::vector icomps; - IntegerType * Int1Ty = IntegerType::getInt1Ty(C); + LLVMContext &C = M.getContext(); + IntegerType *Int1Ty = IntegerType::getInt1Ty(C); - /* iterate over all functions, bbs and instruction and add - * all integer comparisons with >= and <= predicates to the icomps vector */ - for (auto &F : M) { + /* find out what the new predicate is going to be */ + auto cmp_inst = dyn_cast(IcmpInst); + if (!cmp_inst) { return false; } - if (!isInInstrumentList(&F)) continue; + BasicBlock *bb = IcmpInst->getParent(); - for (auto &BB : F) { + auto op0 = IcmpInst->getOperand(0); + auto op1 = IcmpInst->getOperand(1); - for (auto &IN : BB) { + CmpInst::Predicate pred = cmp_inst->getPredicate(); + CmpInst::Predicate new_pred; - CmpInst *selectcmpInst = nullptr; + switch (pred) { - if ((selectcmpInst = dyn_cast(&IN))) { + case CmpInst::ICMP_UGE: + new_pred = CmpInst::ICMP_UGT; + break; + case CmpInst::ICMP_SGE: + new_pred = CmpInst::ICMP_SGT; + break; + case CmpInst::ICMP_ULE: + new_pred = CmpInst::ICMP_ULT; + break; + case CmpInst::ICMP_SLE: + new_pred = CmpInst::ICMP_SLT; + break; + default: // keep the compiler happy + return false; - if (selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || - selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) { + } - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); + /* split before the icmp instruction */ + BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); + + /* the old bb now contains a unconditional jump to the new one (end_bb) + * we need to delete it later */ + + /* create the ICMP instruction with new_pred and add it to the old basic + * block bb it is now at the position where the old IcmpInst was */ + CmpInst *icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); + bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), icmp_np); + + /* create a new basic block which holds the new EQ icmp */ + CmpInst *icmp_eq; + /* insert middle_bb before end_bb */ + BasicBlock *middle_bb = + BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); + middle_bb->getInstList().push_back(icmp_eq); + /* add an unconditional branch to the end of middle_bb with destination + * end_bb */ + BranchInst::Create(end_bb, middle_bb); + + /* replace the uncond branch with a conditional one, which depends on the + * new_pred icmp. True goes to end, false to the middle (injected) bb */ + auto term = bb->getTerminator(); + BranchInst::Create(end_bb, middle_bb, icmp_np, bb); + term->eraseFromParent(); + + /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI + * inst to wire up the loose ends */ + PHINode *PN = PHINode::Create(Int1Ty, 2, ""); + /* the first result depends on the outcome of icmp_eq */ + PN->addIncoming(icmp_eq, middle_bb); + /* if the source was the original bb we know that the icmp_np yielded true + * hence we can hardcode this value */ + PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); + /* replace the old IcmpInst with our new and shiny PHI inst */ + BasicBlock::iterator ii(IcmpInst); + ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + + worklist.push_back(icmp_np); + worklist.push_back(icmp_eq); - IntegerType *intTyOp0 = dyn_cast(op0->getType()); - IntegerType *intTyOp1 = dyn_cast(op1->getType()); + return true; - /* this is probably not needed but we do it anyway */ - if (!intTyOp0 || !intTyOp1) { continue; } +} - icomps.push_back(selectcmpInst); +/// Simplify a signed comparison operator by splitting it into a unsigned and +/// bit comparison. add all resulting comparisons to +/// the worklist passed as a reference. +bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, + CmpWorklist &worklist) { - } + LLVMContext &C = M.getContext(); + IntegerType *Int1Ty = IntegerType::getInt1Ty(C); - } + BasicBlock *bb = IcmpInst->getParent(); - } + auto op0 = IcmpInst->getOperand(0); + auto op1 = IcmpInst->getOperand(1); - } + IntegerType *intTyOp0 = dyn_cast(op0->getType()); + if (!intTyOp0) { return false; } + unsigned bitw = intTyOp0->getBitWidth(); + IntegerType *IntType = IntegerType::get(C, bitw); - } + /* get the new predicate */ + auto cmp_inst = dyn_cast(IcmpInst); + if (!cmp_inst) { return false; } + auto pred = cmp_inst->getPredicate(); + CmpInst::Predicate new_pred; - if (!icomps.size()) { return false; } + if (pred == CmpInst::ICMP_SGT) { - for (auto &IcmpInst : icomps) { + new_pred = CmpInst::ICMP_UGT; - BasicBlock *bb = IcmpInst->getParent(); + } else { - auto op0 = IcmpInst->getOperand(0); - auto op1 = IcmpInst->getOperand(1); + new_pred = CmpInst::ICMP_ULT; - /* find out what the new predicate is going to be */ - auto cmp_inst = dyn_cast(IcmpInst); - if (!cmp_inst) { continue; } - auto pred = cmp_inst->getPredicate(); - CmpInst::Predicate new_pred; + } - switch (pred) { + BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); + + /* create a 1 bit compare for the sign bit. to do this shift and trunc + * the original operands so only the first bit remains.*/ + Value *s_op0, *t_op0, *s_op1, *t_op1, *icmp_sign_bit; + + IRBuilder<> IRB(bb->getTerminator()); + s_op0 = IRB.CreateLShr(op0, ConstantInt::get(IntType, bitw - 1)); + t_op0 = IRB.CreateTruncOrBitCast(s_op0, Int1Ty); + s_op1 = IRB.CreateLShr(op1, ConstantInt::get(IntType, bitw - 1)); + t_op1 = IRB.CreateTruncOrBitCast(s_op1, Int1Ty); + /* compare of the sign bits */ + icmp_sign_bit = IRB.CreateICmp(CmpInst::ICMP_EQ, t_op0, t_op1); + + /* create a new basic block which is executed if the signedness bit is + * different */ + CmpInst * icmp_inv_sig_cmp; + BasicBlock *sign_bb = + BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); + if (pred == CmpInst::ICMP_SGT) { + + /* if we check for > and the op0 positive and op1 negative then the final + * result is true. if op0 negative and op1 pos, the cmp must result + * in false + */ + icmp_inv_sig_cmp = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); - case CmpInst::ICMP_UGE: - new_pred = CmpInst::ICMP_UGT; - break; - case CmpInst::ICMP_SGE: - new_pred = CmpInst::ICMP_SGT; - break; - case CmpInst::ICMP_ULE: - new_pred = CmpInst::ICMP_ULT; - break; - case CmpInst::ICMP_SLE: - new_pred = CmpInst::ICMP_SLT; - break; - default: // keep the compiler happy - continue; + } else { - } + /* just the inverse of the above statement */ + icmp_inv_sig_cmp = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); - /* split before the icmp instruction */ - BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); + } - /* the old bb now contains a unconditional jump to the new one (end_bb) - * we need to delete it later */ + sign_bb->getInstList().push_back(icmp_inv_sig_cmp); + BranchInst::Create(end_bb, sign_bb); - /* create the ICMP instruction with new_pred and add it to the old basic - * block bb it is now at the position where the old IcmpInst was */ - Instruction *icmp_np; - icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - icmp_np); + /* create a new bb which is executed if signedness is equal */ + CmpInst * icmp_usign_cmp; + BasicBlock *middle_bb = + BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + /* we can do a normal unsigned compare now */ + icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); - /* create a new basic block which holds the new EQ icmp */ - Instruction *icmp_eq; - /* insert middle_bb before end_bb */ - BasicBlock *middle_bb = - BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1); - middle_bb->getInstList().push_back(icmp_eq); - /* add an unconditional branch to the end of middle_bb with destination - * end_bb */ - BranchInst::Create(end_bb, middle_bb); + middle_bb->getInstList().push_back(icmp_usign_cmp); + BranchInst::Create(end_bb, middle_bb); - /* replace the uncond branch with a conditional one, which depends on the - * new_pred icmp. True goes to end, false to the middle (injected) bb */ - auto term = bb->getTerminator(); - BranchInst::Create(end_bb, middle_bb, icmp_np, bb); - term->eraseFromParent(); + auto term = bb->getTerminator(); + /* if the sign is eq do a normal unsigned cmp, else we have to check the + * signedness bit */ + BranchInst::Create(middle_bb, sign_bb, icmp_sign_bit, bb); + term->eraseFromParent(); - /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI - * inst to wire up the loose ends */ - PHINode *PN = PHINode::Create(Int1Ty, 2, ""); - /* the first result depends on the outcome of icmp_eq */ - PN->addIncoming(icmp_eq, middle_bb); - /* if the source was the original bb we know that the icmp_np yielded true - * hence we can hardcode this value */ - PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); - /* replace the old IcmpInst with our new and shiny PHI inst */ - BasicBlock::iterator ii(IcmpInst); - ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + PHINode *PN = PHINode::Create(Int1Ty, 2, ""); - } + PN->addIncoming(icmp_usign_cmp, middle_bb); + PN->addIncoming(icmp_inv_sig_cmp, sign_bb); + + BasicBlock::iterator ii(IcmpInst); + ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + + // save for later + worklist.push_back(icmp_usign_cmp); + + // signed comparisons are not supported by the splitting code, so we must not + // add it to the worklist. + // worklist.push_back(icmp_inv_sig_cmp); return true; } -/* this function transforms signed compares to equivalent unsigned compares */ -bool SplitComparesTransform::simplifyIntSignedness(Module &M) { +bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, + CmpWorklist &worklist) { - LLVMContext & C = M.getContext(); - std::vector icomps; - IntegerType * Int1Ty = IntegerType::getInt1Ty(C); + auto pred = cmp_inst->getPredicate(); + switch (pred) { - /* iterate over all functions, bbs and instructions and add - * all signed compares to icomps vector */ - for (auto &F : M) { + case CmpInst::ICMP_EQ: + case CmpInst::ICMP_NE: + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_ULT: + break; + default: + // unsupported predicate! + return false; - if (!isInInstrumentList(&F)) continue; + } - for (auto &BB : F) { + auto op0 = cmp_inst->getOperand(0); + auto op1 = cmp_inst->getOperand(1); - for (auto &IN : BB) { + // get bitwidth by checking the bitwidth of the first operator + IntegerType *intTyOp0 = dyn_cast(op0->getType()); + if (!intTyOp0) { - CmpInst *selectcmpInst = nullptr; + // not an integer type + return false; - if ((selectcmpInst = dyn_cast(&IN))) { + } - if (selectcmpInst->getPredicate() == CmpInst::ICMP_SGT || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLT) { + unsigned bitw = intTyOp0->getBitWidth(); + if (bitw == target_bitwidth) { - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); + // already the target bitwidth so we have to do nothing here. + return true; + + } + + LLVMContext &C = M.getContext(); + IntegerType *Int1Ty = IntegerType::getInt1Ty(C); + BasicBlock * bb = cmp_inst->getParent(); + IntegerType *OldIntType = IntegerType::get(C, bitw); + IntegerType *NewIntType = IntegerType::get(C, bitw / 2); + BasicBlock * end_bb = bb->splitBasicBlock(BasicBlock::iterator(cmp_inst)); + CmpInst * icmp_high, *icmp_low; - IntegerType *intTyOp0 = dyn_cast(op0->getType()); - IntegerType *intTyOp1 = dyn_cast(op1->getType()); + /* create the comparison of the top halves of the original operands */ + Value *s_op0, *op0_high, *s_op1, *op1_high; - /* see above */ - if (!intTyOp0 || !intTyOp1) { continue; } + IRBuilder<> IRB(bb->getTerminator()); - /* i think this is not possible but to lazy to look it up */ - if (intTyOp0->getBitWidth() != intTyOp1->getBitWidth()) { + s_op0 = IRB.CreateBinOp(Instruction::LShr, op0, + ConstantInt::get(OldIntType, bitw / 2)); + op0_high = IRB.CreateTruncOrBitCast(s_op0, NewIntType); - continue; + s_op1 = IRB.CreateBinOp(Instruction::LShr, op1, + ConstantInt::get(OldIntType, bitw / 2)); + op1_high = IRB.CreateTruncOrBitCast(s_op1, NewIntType); + icmp_high = cast(IRB.CreateICmp(pred, op0_high, op1_high)); - } + PHINode *PN = nullptr; - icomps.push_back(selectcmpInst); + /* now we have to destinguish between == != and > < */ + switch (pred) { - } + case CmpInst::ICMP_EQ: + case CmpInst::ICMP_NE: { - } + /* transformation for == and != icmps */ + + /* create a compare for the lower half of the original operands */ + BasicBlock *cmp_low_bb = + BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); + + Value * op0_low, *op1_low; + IRBuilder<> Builder(cmp_low_bb); + + op0_low = Builder.CreateTrunc(op0, NewIntType); + op1_low = Builder.CreateTrunc(op1, NewIntType); + icmp_low = cast(Builder.CreateICmp(pred, op0_low, op1_low)); + + BranchInst::Create(end_bb, cmp_low_bb); + + /* 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; + if (pred == CmpInst::ICMP_EQ) { + + br = 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); } + term->eraseFromParent(); + + /* create the PHI and connect the edges accordingly */ + PN = PHINode::Create(Int1Ty, 2, ""); + PN->addIncoming(icmp_low, cmp_low_bb); + Value *val = nullptr; + if (pred == CmpInst::ICMP_EQ) { + + val = ConstantInt::get(Int1Ty, 0); + + } else { + + /* CmpInst::ICMP_NE */ + val = ConstantInt::get(Int1Ty, 1); + + } + + PN->addIncoming(val, icmp_high->getParent()); + break; + } - } + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_ULT: { + + /* transformations for < and > */ + + /* create a basic block which checks for the inverse predicate. + * if this is true we can go to the end if not we have to go to the + * bb which checks the lower half of the operands */ + Instruction *op0_low, *op1_low; + CmpInst * icmp_inv_cmp = nullptr; + BasicBlock * inv_cmp_bb = + BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); + if (pred == CmpInst::ICMP_UGT) { - if (!icomps.size()) { return false; } + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, + op0_high, op1_high); - for (auto &IcmpInst : icomps) { + } else { - BasicBlock *bb = IcmpInst->getParent(); + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, + op0_high, op1_high); - auto op0 = IcmpInst->getOperand(0); - auto op1 = IcmpInst->getOperand(1); + } - IntegerType *intTyOp0 = dyn_cast(op0->getType()); - if (!intTyOp0) { continue; } - unsigned bitw = intTyOp0->getBitWidth(); - IntegerType *IntType = IntegerType::get(C, bitw); + inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); + worklist.push_back(icmp_inv_cmp); - /* get the new predicate */ - auto cmp_inst = dyn_cast(IcmpInst); - if (!cmp_inst) { continue; } - auto pred = cmp_inst->getPredicate(); - CmpInst::Predicate new_pred; + auto term = bb->getTerminator(); + term->eraseFromParent(); + BranchInst::Create(end_bb, inv_cmp_bb, icmp_high, bb); - if (pred == CmpInst::ICMP_SGT) { + /* create a bb which handles the cmp of the lower halves */ + BasicBlock *cmp_low_bb = + BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); + op0_low = new TruncInst(op0, NewIntType); + cmp_low_bb->getInstList().push_back(op0_low); + op1_low = new TruncInst(op1, NewIntType); + cmp_low_bb->getInstList().push_back(op1_low); - new_pred = CmpInst::ICMP_UGT; + icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low); + cmp_low_bb->getInstList().push_back(icmp_low); + BranchInst::Create(end_bb, cmp_low_bb); - } else { + BranchInst::Create(end_bb, cmp_low_bb, icmp_inv_cmp, inv_cmp_bb); - new_pred = CmpInst::ICMP_ULT; + PN = PHINode::Create(Int1Ty, 3); + PN->addIncoming(icmp_low, cmp_low_bb); + PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); + PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb); + break; } - BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); + default: + return false; - /* create a 1 bit compare for the sign bit. to do this shift and trunc - * the original operands so only the first bit remains.*/ - Instruction *s_op0, *t_op0, *s_op1, *t_op1, *icmp_sign_bit; + } - s_op0 = BinaryOperator::Create(Instruction::LShr, op0, - ConstantInt::get(IntType, bitw - 1)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_op0); - t_op0 = new TruncInst(s_op0, Int1Ty); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), t_op0); + BasicBlock::iterator ii(cmp_inst); + ReplaceInstWithInst(cmp_inst->getParent()->getInstList(), ii, PN); - s_op1 = BinaryOperator::Create(Instruction::LShr, op1, - ConstantInt::get(IntType, bitw - 1)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_op1); - t_op1 = new TruncInst(s_op1, Int1Ty); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), t_op1); + // We split the comparison into low and high. If this isn't our target + // bitwidth we recursivly split the low and high parts again until we have + // target bitwidth. + if ((bitw / 2) > target_bitwidth) { - /* compare of the sign bits */ - icmp_sign_bit = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_op0, t_op1); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - icmp_sign_bit); + worklist.push_back(icmp_high); + worklist.push_back(icmp_low); - /* create a new basic block which is executed if the signedness bit is - * different */ - Instruction *icmp_inv_sig_cmp; - BasicBlock * sign_bb = - BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); - if (pred == CmpInst::ICMP_SGT) { + } - /* if we check for > and the op0 positive and op1 negative then the final - * result is true. if op0 negative and op1 pos, the cmp must result - * in false - */ - icmp_inv_sig_cmp = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); + return true; - } else { +} + +bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { + + CmpWorklist worklist; + + auto op0 = I->getOperand(0); + auto op1 = I->getOperand(1); + if (!op0 || !op1) { return false; } + auto op0Ty = dyn_cast(op0->getType()); + if (!op0Ty || !isa(op1->getType())) { return true; } + + unsigned bitw = op0Ty->getBitWidth(); + +#ifdef VERIFY_TOO_MUCH + auto F = I->getParent()->getParent(); +#endif + + // we run the comparison simplification on all compares regardless of their + // bitwidth. + if (I->getPredicate() == CmpInst::ICMP_UGE || + I->getPredicate() == CmpInst::ICMP_SGE || + I->getPredicate() == CmpInst::ICMP_ULE || + I->getPredicate() == CmpInst::ICMP_SLE) { - /* just the inverse of the above statement */ - icmp_inv_sig_cmp = - CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); + if (!simplifyOrEqualsCompare(I, M, worklist)) { + + reportError( + "Failed to simplify inequality or equals comparison " + "(UGE,SGE,ULE,SLE)", + I, M); } - sign_bb->getInstList().push_back(icmp_inv_sig_cmp); - BranchInst::Create(end_bb, sign_bb); + } else if (I->getPredicate() == CmpInst::ICMP_SGT || - /* create a new bb which is executed if signedness is equal */ - Instruction *icmp_usign_cmp; - BasicBlock * middle_bb = - BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - /* we can do a normal unsigned compare now */ - icmp_usign_cmp = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1); - middle_bb->getInstList().push_back(icmp_usign_cmp); - BranchInst::Create(end_bb, middle_bb); + I->getPredicate() == CmpInst::ICMP_SLT) { - auto term = bb->getTerminator(); - /* if the sign is eq do a normal unsigned cmp, else we have to check the - * signedness bit */ - BranchInst::Create(middle_bb, sign_bb, icmp_sign_bit, bb); - term->eraseFromParent(); + if (!simplifySignedCompare(I, M, worklist)) { - PHINode *PN = PHINode::Create(Int1Ty, 2, ""); + reportError("Failed to simplify signed comparison (SGT,SLT)", I, M); + + } + + } + +#ifdef VERIFY_TOO_MUCH + if (verifyFunction(*F, &errs())) { + + reportError("simpliyfing compare lead to broken function", nullptr, M); + + } + +#endif + + // the simplification methods replace the original CmpInst and push the + // resulting new CmpInst into the worklist. If the worklist is empty then + // we only have to split the original CmpInst. + if (worklist.size() == 0) { worklist.push_back(I); } + + while (!worklist.empty()) { + + CmpInst *cmp = worklist.pop_back_val(); + // we split the simplified compares into comparisons with smaller bitwidths + // if they are larger than our target_bitwidth. + if (bitw > target_bitwidth) { + + if (!splitCompare(cmp, M, worklist)) { + + reportError("Failed to split comparison", cmp, M); + + } + +#ifdef VERIFY_TOO_MUCH + if (verifyFunction(*F, &errs())) { + + reportError("splitting compare lead to broken function", nullptr, M); + + } - PN->addIncoming(icmp_usign_cmp, middle_bb); - PN->addIncoming(icmp_inv_sig_cmp, sign_bb); +#endif - BasicBlock::iterator ii(IcmpInst); - ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + } } + count++; return true; } @@ -1050,306 +1316,108 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } -/* splits icmps of size bitw into two nested icmps with bitw/2 size each */ -size_t SplitComparesTransform::splitIntCompares(Module &M, unsigned bitw) { - - size_t count = 0; - - LLVMContext &C = M.getContext(); - - IntegerType *Int1Ty = IntegerType::getInt1Ty(C); - IntegerType *OldIntType = IntegerType::get(C, bitw); - IntegerType *NewIntType = IntegerType::get(C, bitw / 2); - - std::vector icomps; - - if (bitw % 2) { return 0; } - - /* not supported yet */ - if (bitw > 64) { return 0; } - - /* get all EQ, NE, UGT, and ULT icmps of width bitw. if the - * functions simplifyCompares() and simplifyIntSignedness() - * were executed only these four predicates should exist */ - for (auto &F : M) { - - if (!isInInstrumentList(&F)) continue; - - for (auto &BB : F) { +bool SplitComparesTransform::runOnModule(Module &M) { - for (auto &IN : BB) { + char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); + if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); + if (bitw_env) { target_bitwidth = atoi(bitw_env); } - CmpInst *selectcmpInst = nullptr; + enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL; - if ((selectcmpInst = dyn_cast(&IN))) { + if ((isatty(2) && getenv("AFL_QUIET") == NULL) || + getenv("AFL_DEBUG") != NULL) { - if (selectcmpInst->getPredicate() == CmpInst::ICMP_EQ || - selectcmpInst->getPredicate() == CmpInst::ICMP_NE || - selectcmpInst->getPredicate() == CmpInst::ICMP_UGT || - selectcmpInst->getPredicate() == CmpInst::ICMP_ULT) { + errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " + "heiko@hexco.de (splitting icmp to " + << target_bitwidth << " bit)\n"; - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); + if (getenv("AFL_DEBUG") != NULL && !debug) { debug = 1; } - IntegerType *intTyOp0 = dyn_cast(op0->getType()); - IntegerType *intTyOp1 = dyn_cast(op1->getType()); + } else { - if (!intTyOp0 || !intTyOp1) { continue; } + be_quiet = 1; - /* check if the bitwidths are the one we are looking for */ - if (intTyOp0->getBitWidth() != bitw || - intTyOp1->getBitWidth() != bitw) { + } - continue; + if (enableFPSplit) { - } + count = splitFPCompares(M); - icomps.push_back(selectcmpInst); + /* + if (!be_quiet) { - } + errs() << "Split-floatingpoint-compare-pass: " << count + << " FP comparisons split\n"; } - } - - } + */ + simplifyFPCompares(M); } - if (!icomps.size()) { return 0; } - - for (auto &IcmpInst : icomps) { - - BasicBlock *bb = IcmpInst->getParent(); - - auto op0 = IcmpInst->getOperand(0); - auto op1 = IcmpInst->getOperand(1); - - auto cmp_inst = dyn_cast(IcmpInst); - if (!cmp_inst) { continue; } - auto pred = cmp_inst->getPredicate(); - - BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); - - /* create the comparison of the top halves of the original operands */ - Instruction *s_op0, *op0_high, *s_op1, *op1_high, *icmp_high; - - s_op0 = BinaryOperator::Create(Instruction::LShr, op0, - ConstantInt::get(OldIntType, bitw / 2)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_op0); - op0_high = new TruncInst(s_op0, NewIntType); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - op0_high); - - s_op1 = BinaryOperator::Create(Instruction::LShr, op1, - ConstantInt::get(OldIntType, bitw / 2)); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), s_op1); - op1_high = new TruncInst(s_op1, NewIntType); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - op1_high); - - icmp_high = CmpInst::Create(Instruction::ICmp, pred, op0_high, op1_high); - bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()), - icmp_high); - - /* now we have to destinguish between == != and > < */ - if (pred == CmpInst::ICMP_EQ || pred == CmpInst::ICMP_NE) { - - /* transformation for == and != icmps */ - - /* create a compare for the lower half of the original operands */ - Instruction *op0_low, *op1_low, *icmp_low; - BasicBlock * cmp_low_bb = - BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - - op0_low = new TruncInst(op0, NewIntType); - cmp_low_bb->getInstList().push_back(op0_low); - - op1_low = new TruncInst(op1, NewIntType); - cmp_low_bb->getInstList().push_back(op1_low); - - icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low); - cmp_low_bb->getInstList().push_back(icmp_low); - BranchInst::Create(end_bb, cmp_low_bb); - - /* dependent on the cmp of the high parts go to the end or go on with - * the comparison */ - auto term = bb->getTerminator(); - if (pred == CmpInst::ICMP_EQ) { - - BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb); - - } else { - - /* CmpInst::ICMP_NE */ - BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb); - - } - - term->eraseFromParent(); - - /* create the PHI and connect the edges accordingly */ - PHINode *PN = PHINode::Create(Int1Ty, 2, ""); - PN->addIncoming(icmp_low, cmp_low_bb); - if (pred == CmpInst::ICMP_EQ) { - - PN->addIncoming(ConstantInt::get(Int1Ty, 0), bb); + std::vector worklist; + /* iterate over all functions, bbs and instruction search for all integer + * compare instructions. Save them into the worklist for later. */ + for (auto &F : M) { - } else { + if (!isInInstrumentList(&F)) continue; - /* CmpInst::ICMP_NE */ - PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); + for (auto &BB : F) { - } + for (auto &IN : BB) { - /* replace the old icmp with the new PHI */ - BasicBlock::iterator ii(IcmpInst); - ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); + if (auto CI = dyn_cast(&IN)) { - } else { + auto op0 = CI->getOperand(0); + auto op1 = CI->getOperand(1); + if (!op0 || !op1) { return false; } + auto iTy1 = dyn_cast(op0->getType()); + if (iTy1 && isa(op1->getType())) { - /* CmpInst::ICMP_UGT and CmpInst::ICMP_ULT */ - /* transformations for < and > */ + unsigned bitw = iTy1->getBitWidth(); + if (isSupportedBitWidth(bitw)) { worklist.push_back(CI); } - /* create a basic block which checks for the inverse predicate. - * if this is true we can go to the end if not we have to go to the - * bb which checks the lower half of the operands */ - Instruction *icmp_inv_cmp, *op0_low, *op1_low, *icmp_low; - BasicBlock * inv_cmp_bb = - BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); - if (pred == CmpInst::ICMP_UGT) { - - icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, - op0_high, op1_high); - - } else { + } - icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, - op0_high, op1_high); + } } - inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); - - auto term = bb->getTerminator(); - term->eraseFromParent(); - BranchInst::Create(end_bb, inv_cmp_bb, icmp_high, bb); - - /* create a bb which handles the cmp of the lower halves */ - BasicBlock *cmp_low_bb = - BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - op0_low = new TruncInst(op0, NewIntType); - cmp_low_bb->getInstList().push_back(op0_low); - op1_low = new TruncInst(op1, NewIntType); - cmp_low_bb->getInstList().push_back(op1_low); - - icmp_low = CmpInst::Create(Instruction::ICmp, pred, op0_low, op1_low); - cmp_low_bb->getInstList().push_back(icmp_low); - BranchInst::Create(end_bb, cmp_low_bb); - - BranchInst::Create(end_bb, cmp_low_bb, icmp_inv_cmp, inv_cmp_bb); - - PHINode *PN = PHINode::Create(Int1Ty, 3); - PN->addIncoming(icmp_low, cmp_low_bb); - PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); - PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb); - - BasicBlock::iterator ii(IcmpInst); - ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN); - } - ++count; - } - return count; - -} - -bool SplitComparesTransform::runOnModule(Module &M) { - - int bitw = 64; - size_t count = 0; - - char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); - if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); - if (bitw_env) { bitw = atoi(bitw_env); } - - enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL; - - if ((isatty(2) && getenv("AFL_QUIET") == NULL) || - getenv("AFL_DEBUG") != NULL) { + // now that we have a list of all integer comparisons we can start replacing + // them with the splitted alternatives. + for (auto CI : worklist) { - printf( - "Split-compare-pass by laf.intel@gmail.com, extended by " - "heiko@hexco.de\n"); - - } else { - - be_quiet = 1; + simplifyAndSplit(CI, M); } - if (enableFPSplit) { - - count = splitFPCompares(M); - - /* - if (!be_quiet) { - - errs() << "Split-floatingpoint-compare-pass: " << count - << " FP comparisons split\n"; + bool brokenDebug = false; + if (verifyModule( M, &errs() +#if LLVM_VERSION_MAJOR > 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 9) + ,&brokenDebug // 9th May 2016 +#endif + )) { - } - - */ - simplifyFPCompares(M); + reportError( + "Module Verifier failed! Consider reporting a bug with the AFL++ " + "project.", + nullptr, M); } - simplifyCompares(M); - - simplifyIntSignedness(M); + if (brokenDebug) { - switch (bitw) { - - case 64: - count += splitIntCompares(M, bitw); - if (debug) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - bitw >>= 1; -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7) - [[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */ -#endif - case 32: - count += splitIntCompares(M, bitw); - if (debug) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - bitw >>= 1; -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 7) - [[clang::fallthrough]]; /*FALLTHRU*/ /* FALLTHROUGH */ -#endif - case 16: - count += splitIntCompares(M, bitw); - if (debug) - errs() << "Split-integer-compare-pass " << bitw << "bit: " << count - << " split\n"; - // bitw >>= 1; - break; - - default: - // if (!be_quiet) errs() << "NOT Running split-compare-pass \n"; - return false; - break; + reportError("Module Verifier reported broken Debug Infos - Stripping!", + nullptr, M); + StripDebugInfo(M); } - verifyModule(M); return true; } @@ -1373,3 +1441,8 @@ static RegisterStandardPasses RegisterSplitComparesTransPassLTO( registerSplitComparesPass); #endif +static RegisterPass X("splitcompares", + "AFL++ split compares", + true /* Only looks at CFG */, + true /* Analysis Pass */); + diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 606254d9..dbf2920f 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -167,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(fsrv.out_file); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -643,12 +643,14 @@ static void set_up_environment(char **argv) { } - fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = + alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } unlink(fsrv.out_file); - fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fsrv.out_fd = + open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } @@ -1118,7 +1120,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv.target_path) { ck_free(fsrv.target_path); } if (in_data) { ck_free(in_data); } - exit(0); } diff --git a/src/afl-common.c b/src/afl-common.c index c61ce3d8..9ca2b3e8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -751,6 +751,8 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { } +/* Get unix time in milliseconds */ + u64 get_cur_time(void) { struct timeval tv; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c3ce2edd..11adebf4 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -73,7 +73,7 @@ static int select_algorithm(afl_state_t *afl, u32 max_algorithm) { /* Helper to choose random block len for block operations in fuzz_one(). Doesn't return zero, provided that max_len is > 0. */ -static u32 choose_block_len(afl_state_t *afl, u32 limit) { +static inline u32 choose_block_len(afl_state_t *afl, u32 limit) { u32 min_value, max_value; u32 rlim = MIN(afl->queue_cycle, (u32)3); diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index b41ffa88..268f726c 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -252,7 +252,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 start_time = get_cur_time(); #endif - u32 screen_update = 1000000 / afl->queue_cur->exec_us; + u32 screen_update; u64 orig_hit_cnt, new_hit_cnt, exec_cksum; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -261,6 +261,24 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, afl->stage_max = (len << 1); afl->stage_cur = 0; + if (likely(afl->queue_cur->exec_us)) { + + if (likely((100000 / 2) >= afl->queue_cur->exec_us)) { + + screen_update = 100000 / afl->queue_cur->exec_us; + + } else { + + screen_update = 1; + + } + + } else { + + screen_update = 100000; + + } + // in colorization we do not classify counts, hence we have to calculate // the original checksum. if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) { @@ -905,17 +923,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..." s64 diff = pattern - b_val; s64 o_diff = o_pattern - o_b_val; - /* - fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, - h->shape + 1, o_pattern, o_b_val, o_diff); - fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, - b_val, diff);*/ + /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, + h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, + b_val, diff); */ if (diff == o_diff && diff) { // this could be an arithmetic transformation u64 new_repl = (u64)((s64)repl - diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -935,15 +952,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, diff = pattern ^ b_val; s64 o_diff = o_pattern ^ o_b_val; - /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (diff == o_diff && diff) { // this could be a XOR transformation u64 new_repl = (u64)((s64)repl ^ diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -982,15 +1001,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1029,15 +1050,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl | (0x2020202020202020 & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1383,7 +1406,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - //#endif /* CMPLOG_SOLVE_ARITHMETIC + //#endif /* + // CMPLOG_SOLVE_ARITHMETIC return 0; @@ -2152,7 +2176,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, memcpy(buf + idx, tmp, i + 1); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, *status); + // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, + // *status); } @@ -2235,7 +2260,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, for (j = 0; j <= i; j++) buf[idx + j] = repl[j] - arith_val[j]; if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status); + // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, + // *status); } @@ -2328,16 +2354,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, /* struct cmp_header *hh = &afl->orig_cmp_map->headers[key]; - fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id, - h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x", - o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr, - "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u - o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v0[j]); - fprintf(stderr, " o1="); - for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v1[j]); - fprintf(stderr, "\n"); + fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, + h->id, h->shape, h->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v0[j]); + fprintf(stderr, " v1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v1[j]); + fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=", + hh->hits, hh->id, hh->shape, hh->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v0[j]); + fprintf(stderr, " o1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v1[j]); + fprintf(stderr, "\n"); */ t = taint; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 493735ff..49856a9f 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -314,7 +314,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, ++q->cal_failed; afl->stage_name = "calibration"; - afl->stage_max = afl->fast_cal ? 3 : CAL_CYCLES; + afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES; /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ @@ -355,6 +355,12 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { + if (unlikely(afl->debug)) { + + DEBUGF("calibration stage %d/%d\n", afl->stage_cur + 1, afl->stage_max); + + } + u64 cksum; write_to_testcase(afl, use_mem, q->len); @@ -402,8 +408,24 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } + if (unlikely(!var_detected)) { + + // note: from_queue seems to only be set during initialization + if (afl->afl_env.afl_no_ui || from_queue) { + + WARNF("instability detected during calibration\n"); + + } else if (afl->debug) { + + DEBUGF("instability detected during calibration\n"); + + } + + } + var_detected = 1; - afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = + afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0658070e..b832c11e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -96,8 +96,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->splicing_with = -1; /* Splicing with which test case? */ afl->cpu_to_bind = -1; afl->havoc_stack_pow2 = HAVOC_STACK_POW2; - afl->cal_cycles = CAL_CYCLES; - afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; afl->exit_on_time = 0; afl->stats_update_freq = 1; @@ -341,6 +339,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_cal_fast = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_FAST_CAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_STATSD", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9a3780fb..e9a67ac5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1276,7 +1276,6 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; } if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; } - if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; } if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; } if (afl->afl_env.afl_autoresume) { @@ -1489,14 +1488,6 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; } - if (afl->afl_env.afl_cal_fast) { - - /* Use less calibration cycles, for slow applications */ - afl->cal_cycles = 3; - afl->cal_cycles_long = 5; - - } - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ diff --git a/test/test-basic.sh b/test/test-basic.sh index b4bb9df2..c39faa74 100755 --- a/test/test-basic.sh +++ b/test/test-basic.sh @@ -56,11 +56,6 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc CODE=1 } # now we want to be sure that afl-fuzz is working - # make sure core_pattern is set to core on linux - (test "$(uname -s)" = "Linux" && test "$(sysctl kernel.core_pattern)" != "kernel.core_pattern = core" && { - $ECHO "$YELLOW[-] we should not run afl-fuzz with enabled core dumps. Run 'sudo sh afl-system-config'.$RESET" - true - }) || # make sure crash reporter is disabled on Mac OS X (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && { $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET" @@ -176,11 +171,6 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc CODE=1 } # now we want to be sure that afl-fuzz is working - # make sure core_pattern is set to core on linux - (test "$(uname -s)" = "Linux" && test "$(sysctl kernel.core_pattern)" != "kernel.core_pattern = core" && { - $ECHO "$YELLOW[-] we should not run afl-fuzz with enabled core dumps. Run 'sudo sh afl-system-config'.$RESET" - true - }) || # make sure crash reporter is disabled on Mac OS X (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && { $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET" diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index 4c36b6c9..50d83e40 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -52,10 +52,6 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && { CODE=1 } # now we want to be sure that afl-fuzz is working - (test "$(uname -s)" = "Linux" && test "$(sysctl kernel.core_pattern)" != "kernel.core_pattern = core" && { - $ECHO "$YELLOW[-] we should not run afl-fuzz with enabled core dumps. Run 'sudo sh afl-system-config'.$RESET" - true - }) || # make sure crash reporter is disabled on Mac OS X (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && { $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET" diff --git a/test/test-int_cases.c b/test/test-int_cases.c new file mode 100644 index 00000000..c76206c5 --- /dev/null +++ b/test/test-int_cases.c @@ -0,0 +1,424 @@ +/* test cases for integer comparison transformations + * compile with -DINT_TYPE="signed char" + * or -DINT_TYPE="short" + * or -DINT_TYPE="int" + * or -DINT_TYPE="long" + * or -DINT_TYPE="long long" + */ + +#include + +int main() { + + volatile INT_TYPE a, b; + /* different values */ + a = -21; + b = -2; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = 1; + b = 8; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 255) { /* short or bigger */ + volatile short a, b; + a = 2; + b = 256+1; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1 - 256; + b = -8; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 65535) { /* int or bigger */ + volatile int a, b; + a = 2; + b = 65536+1; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1 - 65536; + b = -8; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 4294967295) { /* long or bigger */ + volatile long a, b; + a = 2; + b = 4294967296+1; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1 - 4294967296; + b = -8; /* signs equal */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + } + } + } + + a = -1; + b = 1; /* signs differ */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = 0; /* signs differ */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -2; + b = 8; /* signs differ */ + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -2; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 8; + b = 1; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; + a = 1 + 256; + b = 3; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -256; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; + a = 1 + 65536; + b = 3; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -65536; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; + a = 1 + 4294967296; + b = 3; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -4294967296; /* signs equal */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + } + } + } + + a = 1; + b = -1; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 0; + b = -1; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 8; + b = -2; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 1; + b = -2; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; + a = 1 + 256; + b = -2; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -2 - 256; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; + a = 1 + 65536; + b = -2; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -2 - 65536; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; + a = 1 + 4294967296; + b = -2; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = -1; + b = -2 - 4294967296; /* signs differ */ + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + } + } + } + + /* equal values */ + a = 0; + b = 0; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -0; + b = 0; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = 1; + b = 1; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = 5; + b = 5; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -1; + b = -1; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -5; + b = -5; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 255) { + volatile short a, b; + a = 1 + 256; + b = 1 + 256; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -2 - 256; + b = -2 - 256; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 65535) { + volatile int a, b; + a = 1 + 65536; + b = 1 + 65536; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -2 - 65536; + b = -2 - 65536; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((unsigned)(INT_TYPE)(~0) > 4294967295) { + volatile long a, b; + a = 1 + 4294967296; + b = 1 + 4294967296; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = -2 - 4294967296; + b = -2 - 4294967296; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + } + } + } +} + diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 7cdc83cb..8090e176 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -122,10 +122,6 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { CODE=1 } # now we want to be sure that afl-fuzz is working - (test "$(uname -s)" = "Linux" && test "$(sysctl kernel.core_pattern)" != "kernel.core_pattern = core" && { - $ECHO "$YELLOW[-] we should not run afl-fuzz with enabled core dumps. Run 'sudo sh afl-system-config'.$RESET" - true - }) || # make sure crash reporter is disabled on Mac OS X (test "$(uname -s)" = "Darwin" && test $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') && { $ECHO "$RED[!] we cannot run afl-fuzz with enabled crash reporter. Run 'sudo sh afl-system-config'.$RESET" @@ -190,6 +186,29 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { } rm -f test-instr.plain + $ECHO "$GREY[*] llvm_mode laf-intel/compcov testing splitting integer types (this might take some time)" + for testcase in ./test-int_cases.c ./test-uint_cases.c; do + for I in char short int long "long long"; do + for BITS in 8 16 32 64; do + bin="$testcase-split-$I-$BITS.compcov" + AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_COMPARES_BITW=$BITS AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -DINT_TYPE="$I" -o "$bin" "$testcase" > test.out 2>&1; + if ! test -e "$bin"; then + cat test.out + $ECHO "$RED[!] llvm_mode laf-intel/compcov integer splitting failed! ($testcase with type $I split to $BITS)!"; + CODE=1 + break + fi + if ! "$bin"; then + $ECHO "$RED[!] llvm_mode laf-intel/compcov integer splitting resulted in miscompilation (type $I split to $BITS)!"; + CODE=1 + break + fi + rm -f "$bin" test.out || true + done + done + done + rm -f test-int-split*.compcov test.out + AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1 test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && { grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && { diff --git a/test/test-uint_cases.c b/test/test-uint_cases.c new file mode 100644 index 00000000..a277e28a --- /dev/null +++ b/test/test-uint_cases.c @@ -0,0 +1,217 @@ +/* + * compile with -DINT_TYPE="char" + * or -DINT_TYPE="short" + * or -DINT_TYPE="int" + * or -DINT_TYPE="long" + * or -DINT_TYPE="long long" + */ + +#include + +int main() { + + volatile unsigned INT_TYPE a, b; + + a = 1; + b = 8; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; + a = 256+2; + b = 256+21; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = 21; + b = 256+1; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; + a = 65536+2; + b = 65536+21; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = 21; + b = 65536+1; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + } + + if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; + a = 4294967296+2; + b = 4294967296+21; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + + a = 21; + b = 4294967296+1; + assert((a < b)); + assert((a <= b)); + assert(!(a > b)); + assert(!(a >= b)); + assert((a != b)); + assert(!(a == b)); + } + } + + a = 8; + b = 1; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; + a = 256+2; + b = 256+1; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 256+2; + b = 6; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; + a = 65536+2; + b = 65536+1; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 65536+2; + b = 6; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; + a = 4294967296+2; + b = 4294967296+1; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + a = 4294967296+2; + b = 6; + assert((a > b)); + assert((a >= b)); + assert(!(a < b)); + assert(!(a <= b)); + assert((a != b)); + assert(!(a == b)); + + } + } + } + + + a = 0; + b = 0; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + a = 1; + b = 1; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((INT_TYPE)(~0) > 255) { + volatile unsigned short a, b; + a = 256+5; + b = 256+5; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((INT_TYPE)(~0) > 65535) { + volatile unsigned int a, b; + a = 65536+5; + b = 65536+5; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + + if ((INT_TYPE)(~0) > 4294967295) { + volatile unsigned long a, b; + a = 4294967296+5; + b = 4294967296+5; + assert(!(a < b)); + assert((a <= b)); + assert(!(a > b)); + assert((a >= b)); + assert(!(a != b)); + assert((a == b)); + } + } + + } + +} + diff --git a/unicorn_mode/samples/speedtest/rust/src/main.rs b/unicorn_mode/samples/speedtest/rust/src/main.rs index 1e35ff0b..9ea1b873 100644 --- a/unicorn_mode/samples/speedtest/rust/src/main.rs +++ b/unicorn_mode/samples/speedtest/rust/src/main.rs @@ -48,7 +48,7 @@ fn parse_locs(loc_name: &str) -> Result, io::Error> { let contents = &read_file(&format!("../target.offsets.{}", loc_name))?; //println!("Read: {:?}", contents); Ok(str_from_u8_unchecked(&contents) - .split("\n") + .split('\n') .map(|x| { //println!("Trying to convert {}", &x[2..]); let result = u64::from_str_radix(&x[2..], 16); @@ -90,7 +90,8 @@ 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 binary = read_file(BINARY).expect(&format!("Could not read modem image: {}", BINARY)); + let binary = + read_file(BINARY).unwrap_or_else(|_| panic!("Could not read modem image: {}", BINARY)); let _aligned_binary_size = align(binary.len() as u64); // Apply constraints to the mutated input if binary.len() as u64 > CODE_SIZE_MAX { @@ -151,7 +152,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { already_allocated_malloc.set(true); }; - let already_allocated_free = already_allocated.clone(); + 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| { if already_allocated_free.get() { @@ -190,7 +191,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { } for addr in parse_locs("magicfn").unwrap() { - uc.add_code_hook(addr, addr, Box::new(hook_magicfn.clone()))?; + uc.add_code_hook(addr, addr, Box::new(hook_magicfn))?; } let place_input_callback = @@ -225,7 +226,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { match ret { Ok(_) => {} - Err(e) => panic!(format!("found non-ok unicorn exit: {:?}", e)), + Err(e) => panic!("found non-ok unicorn exit: {:?}", e), } Ok(()) diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index c094c425..ff42f3b9 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -204,21 +204,23 @@ static int ExecuteFilesOnyByOne(int argc, char **argv) { int main(int argc, char **argv) { - printf( - "============================== INFO ================================\n" - "This binary is built for afl++.\n" - "To use with afl-cmin or afl-cmin.bash pass '-' as single command line " - "option\n" - "To run the target function on individual input(s) execute this:\n" - " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" - "To fuzz with afl-fuzz execute this:\n" - " afl-fuzz [afl-flags] -- %s [-N]\n" - "afl-fuzz will run N iterations before re-spawning the process (default: " - "INT_MAX)\n" - "For stdin input processing, pass '-' as single command line option.\n" - "For file input processing, pass '@@' as single command line option.\n" - "===================================================================\n", - argv[0], argv[0]); + if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) + printf( + "============================== INFO ================================\n" + "This binary is built for afl++.\n" + "To use with afl-cmin or afl-cmin.bash pass '-' as single command line " + "option\n" + "To run the target function on individual input(s) execute this:\n" + " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" + "To fuzz with afl-fuzz execute this:\n" + " afl-fuzz [afl-flags] -- %s [-N]\n" + "afl-fuzz will run N iterations before re-spawning the process " + "(default: " + "INT_MAX)\n" + "For stdin input processing, pass '-' as single command line option.\n" + "For file input processing, pass '@@' as single command line option.\n" + "===================================================================\n", + argv[0], argv[0]); if (getenv("AFL_GDB")) { -- cgit 1.4.1 From a6c0b5f7667475336a26197d99ea24f18ffcdbd7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 11:46:26 +0200 Subject: afl-cmin/afl-cmin.bash/afl-showmap -i descend into subdirectories --- docs/Changelog.md | 2 + src/afl-showmap.c | 159 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 96 insertions(+), 65 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9f70535a..530dd941 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,8 @@ sending a mail to . - afl_analyze: - fix timeout handling - add forkserver support for better performance + - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into + subdirectories (like afl-fuzz does) - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 96b72dd9..03050d91 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -67,6 +67,8 @@ static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ +static u8 outfile[PATH_MAX]; + static u8 *in_data, /* Input data */ *coverage_map; /* Coverage map */ @@ -88,7 +90,8 @@ static bool quiet_mode, /* Hide non-essential messages? */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ debug, /* debug mode */ - print_filenames; /* print the current filename */ + print_filenames, /* print the current filename */ + wait_for_gdb; static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -692,6 +695,93 @@ static void setup_signal_handlers(void) { } +u32 execute_testcases(u8 *dir) { + + struct dirent **nl; + s32 nl_cnt, subdirs = 1; + u32 i, done = 0; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + + if (!be_quiet) { ACTF("Scanning '%s'...", dir); } + + /* We use scandir() + alphasort() rather than readdir() because otherwise, + the ordering of test cases would vary somewhat randomly and would be + difficult to control. */ + + nl_cnt = scandir(dir, &nl, NULL, alphasort); + + if (nl_cnt < 0) { return 0; } + + for (i = 0; i < (u32)nl_cnt; ++i) { + + struct stat st; + + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + PFATAL("Unable to access '%s'", fn2); + + } + + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + + free(nl[i]); /* not tracked */ + done += execute_testcases(fn2); + ck_free(fn2); + continue; + + } + + free(nl[i]); + + if (!S_ISREG(st.st_mode) || !st.st_size) { + + ck_free(fn2); + continue; + + } + + if (st.st_size > MAX_FILE && !be_quiet) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } + + // DO + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + ++done; + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + free(nl); /* not tracked */ + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -1136,15 +1226,7 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent **file_list; - - // int done = 0; - u8 infile[PATH_MAX], outfile[PATH_MAX]; - u8 wait_for_gdb = 0; -#if !defined(DT_REG) - struct stat statbuf; -#endif + DIR *dir_in, *dir_out = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; @@ -1245,65 +1327,12 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - int file_count = scandir(in_dir, &file_list, NULL, alphasort); - if (file_count < 0) { + if (execute_testcases(in_dir) == 0) { - PFATAL("Failed to read from input dir at %s\n", in_dir); + FATAL("could not read input testcases from %s", in_dir); } - for (int i = 0; i < file_count; i++) { - - struct dirent *dir_ent = file_list[i]; - - if (dir_ent->d_name[0] == '.') { - - continue; // skip anything that starts with '.' - - } - -#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */ - if (dir_ent->d_type != DT_REG) { - - continue; // only regular files - - } - -#endif - - snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name); - -#if !defined(DT_REG) /* use stat() */ - if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; -#endif - - if (!collect_coverage) - snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); - - if (read_file(infile)) { - - if (wait_for_gdb) { - - fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); - fprintf(stderr, "exec: kill -CONT %d\n", getpid()); - kill(0, SIGSTOP); - - } - - showmap_run_target_forkserver(fsrv, in_data, in_len); - ck_free(in_data); - if (collect_coverage) - analyze_results(fsrv); - else - tcnt = write_results_to_file(fsrv, outfile); - - } - - } - - free(file_list); - file_list = NULL; - if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } if (dir_out) { closedir(dir_out); } -- cgit 1.4.1 From c46f8c1f70918056e95c801b1a81f11c79304b05 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 13:03:42 +0200 Subject: make afl-cmin actually work with subdirectories --- afl-cmin | 42 ++++++++++++++++++-------------- docs/Changelog.md | 4 ++-- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-showmap.c | 48 +++++++++++++++++++++---------------- 4 files changed, 54 insertions(+), 42 deletions(-) (limited to 'docs') diff --git a/afl-cmin b/afl-cmin index 9fa63ec6..e71873d3 100755 --- a/afl-cmin +++ b/afl-cmin @@ -296,13 +296,13 @@ BEGIN { exit 1 } - if (0 == system( "test -d "in_dir"/default" )) { - in_dir = in_dir "/default" - } - - if (0 == system( "test -d "in_dir"/queue" )) { - in_dir = in_dir "/queue" - } + #if (0 == system( "test -d "in_dir"/default" )) { + # in_dir = in_dir "/default" + #} + # + #if (0 == system( "test -d "in_dir"/queue" )) { + # in_dir = in_dir "/queue" + #} system("rm -rf "trace_dir" 2>/dev/null"); system("rm "out_dir"/id[:_]* 2>/dev/null") @@ -355,30 +355,35 @@ BEGIN { } else { stat_format = "-f '%z %N'" # *BSD, MacOS } - cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" + cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" while (cmdline | getline) { sub(/^[0-9]+ (\.\/)?/,"",$0) - infilesSmallToBig[i++] = $0 + infilesSmallToBigFull[i] = $0 + sub(/.*\//, "", $0) + infilesSmallToBig[i] = $0 + infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i] + infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i] + i++ } in_count = i - first_file = infilesSmallToBig[0] + first_file = infilesSmallToBigFull[0] - # Make sure that we're not dealing with a directory. - - if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { - print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" - exit 1 - } + #if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { + # print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" + # exit 1 + #} - if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) { + system(">\""in_dir"/.afl-cmin.test\"") + if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) { cp_tool = "ln" } else { cp_tool = "cp" } + system("rm -f \""in_dir"/.afl-cmin.test\"") if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) { # Make sure that we can actually get anything out of afl-showmap before we @@ -511,7 +516,8 @@ BEGIN { # copy file unless already done if (! (fn in file_already_copied)) { - system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"") + realfile = infilesSmallToBigMap[fn] + system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"") file_already_copied[fn] = "" ++out_count #printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log" diff --git a/docs/Changelog.md b/docs/Changelog.md index 530dd941..9fd2a1a9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,8 +31,8 @@ sending a mail to . - afl_analyze: - fix timeout handling - add forkserver support for better performance - - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into - subdirectories (like afl-fuzz does) + - afl-cmin and afl-showmap -i do now descend into subdirectories + (like afl-fuzz does) - note that afl-cmin.bash does not! - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 50117012..404b761f 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1019,7 +1019,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { - write_error("read from afl-fuzz"); + //write_error("read from afl-fuzz"); _exit(1); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 03050d91..646396ad 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -233,7 +233,11 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), caa = !!getenv("AFL_CMIN_ALLOW_ANY"); - if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); } + if (!outfile || !*outfile) { + + FATAL("Output filename not set (Bug in AFL++?)"); + + } if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { @@ -753,7 +757,9 @@ u32 execute_testcases(u8 *dir) { } - // DO + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name); + if (read_file(fn2)) { if (wait_for_gdb) { @@ -800,31 +806,31 @@ static void usage(u8 *argv0) { "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" "Required parameters:\n" - " -o file - file to write the trace data to\n\n" + " -o file - file to write the trace data to\n\n" "Execution control settings:\n" - " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%u MB)\n" - " -O - use binary-only instrumentation (FRIDA mode)\n" - " -Q - use binary-only instrumentation (QEMU mode)\n" - " -U - use Unicorn-based instrumentation (Unicorn mode)\n" - " -W - use qemu-based instrumentation with Wine (Wine mode)\n" - " (Not necessary, here for consistency with other afl-* " + " -t msec - timeout for each run (none)\n" + " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n" + " -U - use Unicorn-based instrumentation (Unicorn mode)\n" + " -W - use qemu-based instrumentation with Wine (Wine mode)\n" + " (Not necessary, here for consistency with other afl-* " "tools)\n\n" "Other settings:\n" - " -i dir - process all files in this directory, must be combined " + " -i dir - process all files below this directory, must be combined " "with -o.\n" - " With -C, -o is a file, without -C it must be a " + " With -C, -o is a file, without -C it must be a " "directory\n" - " and each bitmap will be written there individually.\n" - " -C - collect coverage, writes all edges to -o and gives a " + " and each bitmap will be written there individually.\n" + " -C - collect coverage, writes all edges to -o and gives a " "summary\n" - " Must be combined with -i.\n" - " -q - sink program's output and don't show messages\n" - " -e - show edge coverage only, ignore hit counts\n" - " -r - show real tuple values instead of AFL filter values\n" - " -s - do not classify the map\n" - " -c - allow core dumps\n\n" + " Must be combined with -i.\n" + " -q - sink program's output and don't show messages\n" + " -e - show edge coverage only, ignore hit counts\n" + " -r - show real tuple values instead of AFL filter values\n" + " -s - do not classify the map\n" + " -c - allow core dumps\n\n" "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" @@ -1259,7 +1265,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - if ((coverage_map = (u8 *)malloc(map_size)) == NULL) + if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL) FATAL("coult not grab memory"); edges_only = false; raw_instr_output = true; -- cgit 1.4.1 From 98dc0d26496cb5bcf1af22a3dd852f59637b39cc Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 21 Jun 2021 10:07:14 +0200 Subject: improve documentation --- README.md | 55 ++++++++++++++++++++++++++++++++---------------- docs/parallel_fuzzing.md | 8 +++++-- 2 files changed, 43 insertions(+), 20 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 91f28118..c0a22e54 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,17 @@ For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. -## Major changes in afl++ 3.00 onwards: +## Major behaviour changes in afl++ 3.00 onwards: With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android, iOS etc. +With afl++ 3.14 we introduced the following changes from previous behaviours: + * afl-fuzz: deterministic fuzzing it not a default for -M main anymore + * afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash + however does not) + With afl++ 3.10 we introduced the following changes from previous behaviours: * The '+' feature of the '-t' option now means to auto-calculate the timeout with the value given being the maximum timeout. The original meaning of @@ -38,7 +43,6 @@ With afl++ 3.10 we introduced the following changes from previous behaviours: With afl++ 3.00 we introduced changes that break some previous afl and afl++ behaviours and defaults: - * There are no llvm_mode and gcc_plugin subdirectories anymore and there is only one compiler: afl-cc. All previous compilers now symlink to this one. All instrumentation source code is now in the `instrumentation/` folder. @@ -572,8 +576,15 @@ to use afl-clang-lto as the compiler. You also have the option to generate a dictionary yourself, see [utils/libtokencap/README.md](utils/libtokencap/README.md). afl-fuzz has a variety of options that help to workaround target quirks like -specific locations for the input file (`-f`), not performing deterministic -fuzzing (`-d`) and many more. Check out `afl-fuzz -h`. +specific locations for the input file (`-f`), performing deterministic +fuzzing (`-D`) and many more. Check out `afl-fuzz -h`. + +We highly recommend that you set a memory limit for running the target with `-m` +which defines the maximum memory in MB. This prevents a potential +out-of-memory problem for your system plus helps you detect missing `malloc()` +failure handling in the target. +Play around with various -m values until you find one that safely works for all +your input seeds (if you have good ones and then double or quadrouple that. By default afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C or send a signal SIGINT. You can limit the number of executions or approximate runtime @@ -614,23 +625,28 @@ For every secondary fuzzer there should be a variation, e.g.: * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV fuzzer and you want them to share their intermediate results, the main - fuzzer (`-M`) must be one of the them! + fuzzer (`-M`) must be one of the them! (Although this is not really + recommended.) All other secondaries should be used like this: - * A third to a half with the MOpt mutator enabled: `-L 0` - * run with a different power schedule, available are: - `fast (default), explore, coe, lin, quad, exploit, mmopt, rare, seek` - which you can set with e.g. `-p seek` + * A quarter to a third with the MOpt mutator enabled: `-L 0` + * run with a different power schedule, recommended are: + `fast (default), explore, coe, lin, quad, exploit and rare` + which you can set with e.g. `-p explore` + * a few instances should use the old queue cycling with `-Z` Also it is recommended to set `export AFL_IMPORT_FIRST=1` to load testcases from other fuzzers in the campaign first. +If you have a large corpus, a corpus from a previous run or are fuzzing in +a CI, then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`. + You can also use different fuzzers. If you are using afl spinoffs or afl conforming fuzzers, then just use the same -o directory and give it a unique `-S` name. Examples are: * [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/) - * [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL) + * [symcc](https://github.com/eurecom-s/symcc/) * [AFLsmart](https://github.com/aflsmart/aflsmart) * [FairFuzz](https://github.com/carolemieux/afl-rb) * [Neuzz](https://github.com/Dongdongshe/neuzz) @@ -638,9 +654,11 @@ Examples are: A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL) -However you can also sync afl++ with honggfuzz, libfuzzer with -entropic, etc. +However you can also sync afl++ with honggfuzz, libfuzzer with `-entropic=1`, etc. Just show the main fuzzer (-M) with the `-F` option where the queue/work directory of a different fuzzer is, e.g. `-F /src/target/honggfuzz`. +Using honggfuzz (with `-n 1` or `-n 2`) and libfuzzer in parallel is highly +recommended! #### c) The status of the fuzz campaign @@ -767,25 +785,26 @@ campaigns as these are much shorter runnings. corpus needs to be loaded. * `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new found paths, not the initial corpus as this very likely has been done for them already. - * Keep the generated corpus, use afl-cmin and reuse it everytime! + * Keep the generated corpus, use afl-cmin and reuse it every time! 2. Additionally randomize the afl++ compilation options, e.g. * 40% for `AFL_LLVM_CMPLOG` * 10% for `AFL_LLVM_LAF_ALL` 3. Also randomize the afl-fuzz runtime options, e.g. - * 60% for `AFL_DISABLE_TRIM` + * 65% for `AFL_DISABLE_TRIM` * 50% use a dictionary generated by `AFL_LLVM_DICT2FILE` - * 50% use MOpt (`-L 0`) + * 40% use MOpt (`-L 0`) * 40% for `AFL_EXPAND_HAVOC_NOW` - * 30% for old queue processing (`-Z`) + * 20% for old queue processing (`-Z`) * for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3` 4. Do *not* run any `-M` modes, just running `-S` modes is better for CI fuzzing. - `-M` enables deterministic fuzzing, old queue handling etc. which is good for - a fuzzing campaign but not good for short CI runs. + `-M` enables old queue handling etc. which is good for a fuzzing campaign but + not good for short CI runs. -How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/4bb61df7905c6005000f5766e966e6fe30ab4559/infra/base-images/base-builder/compile_afl#L69). +How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/compile_afl) +and [clusterfuzz](https://github.com/google/clusterfuzz/blob/master/src/python/bot/fuzzers/afl/launcher.py). ## Fuzzing binary-only targets diff --git a/docs/parallel_fuzzing.md b/docs/parallel_fuzzing.md index 8f2afe1b..23872899 100644 --- a/docs/parallel_fuzzing.md +++ b/docs/parallel_fuzzing.md @@ -1,7 +1,11 @@ # Tips for parallel fuzzing - 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. +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) +for up to date strategies! ## 1) Introduction -- cgit 1.4.1 From cbac22d82b90d631bafc4572aa79faa0c568beeb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 22 Jun 2021 17:24:06 +0200 Subject: reverse read the queue n resumes --- docs/Changelog.md | 1 + src/afl-fuzz-init.c | 7 +++++-- src/afl-fuzz-run.c | 3 ++- src/afl-fuzz.c | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9fd2a1a9..afa5491b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,7 @@ sending a mail to . - if the target becomes unavailable check out out/default/error.txt for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL + - reverse read the queue on resumes (more effective) - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 872e3a32..cc5974d8 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -710,7 +710,10 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - for (i = 0; i < (u32)nl_cnt; ++i) { + i = nl_cnt; + do { + + --i; struct stat st; @@ -801,7 +804,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { */ - } + } while (i > 0); free(nl); /* not tracked */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 3de67955..49856a9f 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -424,7 +424,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = + afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c148086c..5f25f728 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1911,7 +1911,12 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); afl->start_time = get_cur_time(); - if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) { + + load_stats_file(afl); + + } + write_stats_file(afl, 0, 0, 0, 0); maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); -- cgit 1.4.1 From ff4d45eed25d9ab80441f813916034bb38cff01e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 22 Jun 2021 22:05:28 +0200 Subject: cmplog fix for qemu and frida --- docs/Changelog.md | 4 +++- instrumentation/afl-compiler-rt.o.c | 17 +++++++++-------- src/afl-forkserver.c | 3 +-- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index afa5491b..4dd68cd2 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -25,10 +25,12 @@ sending a mail to . - support partial linking - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - - fix for cmplog + - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) + - qemu_mode: + - performance fix when cmplog was used - afl_analyze: - fix timeout handling - add forkserver support for better performance diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 92deff6a..d4529e2c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -617,6 +617,7 @@ static void __afl_unmap_shm(void) { #endif __afl_cmp_map = NULL; + __afl_cmp_map_backup = NULL; } @@ -1684,7 +1685,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1788,7 +1789,7 @@ void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) { void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; for (uint64_t i = 0; i < cases[0]; i++) { @@ -1885,7 +1886,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { fprintf(stderr, "\n"); */ - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); int l1, l2; if ((l1 = area_is_valid(ptr1, 32)) <= 0 || @@ -1969,7 +1970,7 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -1979,7 +1980,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -1990,7 +1991,7 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -2000,7 +2001,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -2034,7 +2035,7 @@ void __afl_coverage_on() { if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { __afl_area_ptr = __afl_area_ptr_backup; - __afl_cmp_map = __afl_cmp_map_backup; + if (__afl_cmp_map_backup) { __afl_cmp_map = __afl_cmp_map_backup; } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 8fb8a75a..5e8fb9b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -418,8 +418,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && - fsrv->frida_mode == false) { + if (!fsrv->cmplog_binary) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv -- cgit 1.4.1 From a6cf9bb336cc3e166469d6eed206a2b6fa9c994a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 1 Jul 2021 08:20:32 +0200 Subject: update honggfuzz custom mutator --- custom_mutators/honggfuzz/honggfuzz.h | 5 +++-- docs/Changelog.md | 2 -- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/custom_mutators/honggfuzz/honggfuzz.h b/custom_mutators/honggfuzz/honggfuzz.h index c80cdd87..51c7b567 100644 --- a/custom_mutators/honggfuzz/honggfuzz.h +++ b/custom_mutators/honggfuzz/honggfuzz.h @@ -246,9 +246,9 @@ typedef struct { } timing; struct { struct { - uint8_t val[256]; + uint8_t val[512]; size_t len; - } dictionary[1024]; + } dictionary[8192]; size_t dictionaryCnt; const char* dictionaryFile; size_t mutationsMax; @@ -263,6 +263,7 @@ typedef struct { struct { bool useVerifier; bool exitUponCrash; + uint8_t exitCodeUponCrash; const char* reportFile; size_t dynFileIterExpire; bool only_printable; diff --git a/docs/Changelog.md b/docs/Changelog.md index 475240c2..461acb2c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,8 +29,6 @@ sending a mail to . - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) - - qemu_mode: - - performance fix when cmplog was used - afl-cmin and afl-showmap -i do now descend into subdirectories (like afl-fuzz does) - note that afl-cmin.bash does not! - afl_analyze: diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 0d82727f..019b8715 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 0d82727f2b477de82fa355edef9bc158bd25d374 +Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad -- cgit 1.4.1 From f1bcd378a2e55ee1559dde0d46e2bc32882c5b39 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 7 Jul 2021 12:19:05 +0200 Subject: fix failures for some sized string instrumentations --- docs/Changelog.md | 1 + instrumentation/SanitizerCoverageLTO.so.cc | 12 ++++++++++++ instrumentation/afl-llvm-dict2file.so.cc | 13 ++++++++++++- instrumentation/afl-llvm-lto-instrumentation.so.cc | 7 +++++++ instrumentation/compare-transform-pass.so.cc | 19 +++++-------------- 5 files changed, 37 insertions(+), 15 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 461acb2c..c3e4b34e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix for failures for some sized string instrumentations - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 372af003..28eb0b9f 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -759,6 +759,12 @@ bool ModuleSanitizerCoverage::instrumentModule( uint64_t literalLength = Str2.size(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -862,6 +868,12 @@ bool ModuleSanitizerCoverage::instrumentModule( uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length() + 1) { + + optLen = thestring.length() + 1; + + } + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index e2b44b21..5350f62b 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -428,6 +428,12 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -534,7 +540,12 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); - if (optLen > thestring.length()) { optLen = thestring.length(); } + if (optLen > thestring.length() + 1) { + + optLen = thestring.length() + 1; + + } + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index bb9b9279..263d947d 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -546,6 +546,12 @@ bool AFLLTOPass::runOnModule(Module &M) { uint64_t literalLength = Str2.size(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -649,6 +655,7 @@ bool AFLLTOPass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > literalLength + 1) { optLen = literalLength + 1; } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 3ecba4e6..f5dd4a53 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -313,27 +313,18 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, ConstantInt *ilen = dyn_cast(op2); if (ilen) { - uint64_t len = ilen->getZExtValue(); // if len is zero this is a pointless call but allow real // implementation to worry about that - if (len < 2) continue; + if (ilen->getZExtValue() < 2) { continue; } - if (isMemcmp) { - - // if size of compare is larger than constant string this is - // likely a bug but allow real implementation to worry about - // that - uint64_t literalLength = HasStr1 ? Str1.size() : Str2.size(); - if (literalLength + 1 < ilen->getZExtValue()) continue; - - } - - } else if (isMemcmp) + } else if (isMemcmp) { // this *may* supply a len greater than the constant string at // runtime so similarly we don't want to have to handle that continue; + } + } calls.push_back(callInst); @@ -421,7 +412,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } if (TmpConstStr.length() < 2 || - (TmpConstStr.length() == 2 && !TmpConstStr[1])) { + (TmpConstStr.length() == 2 && TmpConstStr[1] == 0)) { continue; -- cgit 1.4.1 From 37fff16a36c49f47c1a10fcf7c03aa1361a1ae2b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 11 Jul 2021 17:26:31 +0200 Subject: update custom trim --- docs/custom_mutators.md | 4 +--- src/afl-fuzz-mutators.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 129d6676..2c0ca3c5 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -204,9 +204,7 @@ trimmed input. Here's a quick API description: arguments because we already have the initial buffer from `init_trim` and we can memorize the current state in the data variables. This can also save reparsing steps for each iteration. It should return the trimmed input - buffer, where the returned data must not exceed the initial input data in - length. Returning anything that is larger than the original data (passed to - `init_trim`) will result in a fatal abort of AFL++. + buffer. - `post_trim` (optional) diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index e27d6fae..6a77dfbc 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -339,7 +339,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } - while (afl->stage_cur < afl->stage_max) { + while (afl->stage_cur <= afl->stage_max) { u8 *retbuf = NULL; -- cgit 1.4.1 From d16d8dbb8511ad227fdeb33eb5a10914d9ad7bd9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 12 Jul 2021 15:56:25 +0200 Subject: update faq --- docs/FAQ.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/FAQ.md b/docs/FAQ.md index ab0abe6c..0f447044 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -188,13 +188,7 @@ Four steps are required to do this and it also requires quite some knowledge of coding and/or disassembly and is effectively possible only with afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. - 1. First step: Identify which edge ID numbers are unstable - - run the target with `export AFL_DEBUG=1` for a few minutes then terminate. - The out/fuzzer_stats file will then show the edge IDs that were identified - as unstable. - - 2. Second step: Find the responsible function(s). + 1. First step: Instrument to be able to find the responsible function(s). a) For LTO instrumented binaries this can be documented during compile time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`. @@ -217,6 +211,14 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. recompile with the two mentioned above. This is just for identifying the functions that have unstable edges. + 2. Second step: Identify which edge ID numbers are unstable + + run the target with `export AFL_DEBUG=1` for a few minutes then terminate. + The out/fuzzer_stats file will then show the edge IDs that were identified + as unstable in the `var_bytes` entry. You can match these numbers + directly to the data you created in the first step. + Now you know which functions are responsible for the instability + 3. Third step: create a text file with the filenames/functions Identify which source code files contain the functions that you need to -- cgit 1.4.1 From b6a9e54c60e98e5c27404253295ce06648bcbd18 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 13 Jul 2021 11:03:30 +0200 Subject: Added more AFL_NO_FORKSRV docu, changelog --- afl-cmin | 1 + afl-cmin.bash | 1 + docs/Changelog.md | 2 ++ 3 files changed, 4 insertions(+) (limited to 'docs') diff --git a/afl-cmin b/afl-cmin index e71873d3..e6f8c175 100755 --- a/afl-cmin +++ b/afl-cmin @@ -122,6 +122,7 @@ function usage() { "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ +"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \ "AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ "printed to stdout\n" \ diff --git a/afl-cmin.bash b/afl-cmin.bash index f4bd269d..c77dfbc1 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -135,6 +135,7 @@ For additional tips, please consult README.md. Environment variables used: AFL_KEEP_TRACES: leave the temporary \.traces directory +AFL_NO_FORKSRV: run target via execve instead of using the forkserver AFL_PATH: last resort location to find the afl-showmap binary AFL_SKIP_BIN_CHECK: skip check for target binary _EOF_ diff --git a/docs/Changelog.md b/docs/Changelog.md index c3e4b34e..aebd3fa9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -36,6 +36,8 @@ sending a mail to . - fix timeout handling - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module + - added `AFL_NO_FORKSRV` env variable support to + afl-cmin, afl-tmin, and afl-showmap, by @jhertz ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 -- cgit 1.4.1 From 3a3ef7b6b4efcd8ed12bef80cca51f82e65a985f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 12:16:52 +0200 Subject: update documentation --- README.md | 55 ++++++++++++- docs/Changelog.md | 1 + docs/QuickStartGuide.md | 9 +-- docs/README.MOpt.md | 54 ------------- docs/historical_notes.md | 143 -------------------------------- docs/notes_for_asan.md | 157 ------------------------------------ docs/perf_tips.md | 47 ++++------- docs/power_schedules.md | 32 -------- docs/technical_details.md | 4 + instrumentation/afl-compiler-rt.o.c | 5 +- 10 files changed, 79 insertions(+), 428 deletions(-) delete mode 100644 docs/README.MOpt.md delete mode 100644 docs/historical_notes.md delete mode 100644 docs/notes_for_asan.md delete mode 100644 docs/power_schedules.md (limited to 'docs') diff --git a/README.md b/README.md index bc5b333c..50f514ab 100644 --- a/README.md +++ b/README.md @@ -387,7 +387,56 @@ afl++ performs "never zero" counting in its bitmap. You can read more about this here: * [instrumentation/README.neverzero.md](instrumentation/README.neverzero.md) -#### c) Modify the target +#### c) Sanitizers + +It is possible to use sanitizers when instrumenting targets for fuzzing, +which allows you to find bugs that would not necessarily result in a crash. + +Note that sanitizers have a huge impact on CPU (= less executions per second) +and RAM usage. Also you should only run one afl-fuz instance per sanitizer type. +This is enough because a user-after-free bug will be picked up, e.g. by +ASAN (address sanitizer) anyway when syncing to other fuzzing instances, +so not all fuzzing instances need to be instrumented with ASAN. + +The wolloing sanitizers have built-in support in afl++: + * ASAN = Address SANitizer, finds memory corruption vulnerabilities like + use-after-free, NULL pointer dereference, buffer overruns, etc. + Enabled with `export AFL_USE_ASAN=1` before compiling. + * MSAN = Memory SANitizer, finds read access to uninitialized memory, eg. + a local variable that is defined and read before it is even set. + Enabled with `export AFL_USE_MSAN=1` before compiling. + * UBSAN = Undefined Behaviour SANitizer, finds instances where - by the + C and C++ standards - undefined behaviour happens, e.g. adding two + signed integers together where the result is larger than a signed integer + can hold. + Enabled with `export AFL_USE_UBSAN=1` before compiling. + * CFISAN = Control Flow Integrity SANitizer, finds instances where the + control flow is found to be illegal. Originally this was rather to + prevent return oriented programming exploit chains from functioning, + in fuzzing this is mostly reduced to detecting type confusion + vulnerabilities - which is however one of the most important and dangerous + C++ memory corruption classes! + Enabled with `export AFL_USE_CFISAN=1` before compiling. + * LSAN = Leak SANitizer, finds memory leaks in a program. This is not really + a security issue, but for developers this can be very valuable. + Note that unlike the other sanitizers above this needs + `__AFL_LEAK_CHECK();` added to all areas of the target source code where you + find a leak check necessary! + Enabled with `export AFL_USE_LSAN=1` before compiling. + +It is possible to further modify the behaviour of the sanitizers at run-time +by setting `ASAN_OPTIONS=...`, `LSAN_OPTIONS` etc. - the availabel parameter +can be looked up in the sanitizer documentation of llvm/clang. +afl-fuzz however requires some specific parameters important for fuzzing to be +set if you want to set your own, and will bail and report what it is missing. + +Note that some sanitizers cannot be used together, e.g. ASAN and MSAN, and +others often cannot work together because of target weirdness, e.g. ASAN and +CFISAN. You might need to experiment which sanitizers you can combine in a +target (which means more instances can be run without a sanitized target, +which is more effective). + +#### d) Modify the target If the target has features that make fuzzing more difficult, e.g. checksums, HMAC, etc. then modify the source code so that this is @@ -405,7 +454,7 @@ these checks within this specific defines: All afl++ compilers will set this preprocessor definition automatically. -#### d) Instrument the target +#### e) Instrument the target In this step the target source code is compiled so that it can be fuzzed. @@ -462,7 +511,7 @@ non-standard way to set this, otherwise set up the build normally and edit the generated build environment afterwards manually to point it to the right compiler (and/or ranlib and ar). -#### d) Better instrumentation +#### f) Better instrumentation If you just fuzz a target program as-is you are wasting a great opportunity for much more fuzzing speed. diff --git a/docs/Changelog.md b/docs/Changelog.md index aebd3fa9..705daa40 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -38,6 +38,7 @@ sending a mail to . - ensure afl-compiler-rt is built for gcc_module - added `AFL_NO_FORKSRV` env variable support to afl-cmin, afl-tmin, and afl-showmap, by @jhertz + - removed outdated documents, improved existing documentation ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index d1966170..2d056ecf 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -18,14 +18,12 @@ how to hit the ground running: custom SIGSEGV or SIGABRT handlers and background processes. For tips on detecting non-crashing flaws, see section 11 in [README.md](README.md) . -3) Compile the program / library to be fuzzed using afl-gcc. A common way to +3) Compile the program / library to be fuzzed using afl-cc. A common way to do this would be: - CC=/path/to/afl-gcc CXX=/path/to/afl-g++ ./configure --disable-shared + CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared make clean all - If program build fails, ping . - 4) 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, too. @@ -41,9 +39,6 @@ how to hit the ground running: 6) Investigate anything shown in red in the fuzzer UI by promptly consulting [status_screen.md](status_screen.md). -7) compile and use llvm_mode (afl-clang-fast/afl-clang-fast++) as it is way - faster and has a few cool features - 8) There is a basic docker build with 'docker build -t aflplusplus .' That's it. Sit back, relax, and - time permitting - try to skim through the diff --git a/docs/README.MOpt.md b/docs/README.MOpt.md deleted file mode 100644 index 3de6d670..00000000 --- a/docs/README.MOpt.md +++ /dev/null @@ -1,54 +0,0 @@ -# MOpt(imized) AFL by - -### 1. Description -MOpt-AFL is a AFL-based fuzzer that utilizes a customized Particle Swarm -Optimization (PSO) algorithm to find the optimal selection probability -distribution of operators with respect to fuzzing effectiveness. -More details can be found in the technical report. - -### 2. Cite Information -Chenyang Lyu, Shouling Ji, Chao Zhang, Yuwei Li, Wei-Han Lee, Yu Song and -Raheem Beyah, MOPT: Optimized Mutation Scheduling for Fuzzers, -USENIX Security 2019. - -### 3. Seed Sets -We open source all the seed sets used in the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers". - -### 4. Experiment Results -The experiment results can be found in -https://drive.google.com/drive/folders/184GOzkZGls1H2NuLuUfSp9gfqp1E2-lL?usp=sharing. -We only open source the crash files since the space is limited. - -### 5. Technical Report -MOpt_TechReport.pdf is the technical report of the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers", which contains more deatails. - -### 6. Parameter Introduction -Most important, you must add the parameter `-L` (e.g., `-L 0`) to launch the -MOpt scheme. - -Option '-L' controls the time to move on to the pacemaker fuzzing mode. -'-L t': when MOpt-AFL finishes the mutation of one input, if it has not -discovered any new unique crash or path for more than t minutes, MOpt-AFL will -enter the pacemaker fuzzing mode. - -Setting 0 will enter the pacemaker fuzzing mode at first, which is -recommended in a short time-scale evaluation. - -Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in -parallel. - -Other important parameters can be found in afl-fuzz.c, for instance, - -'swarm_num': the number of the PSO swarms used in the fuzzing process. -'period_pilot': how many times MOpt-AFL will execute the target program - in the pilot fuzzing module, then it will enter the core fuzzing module. -'period_core': how many times MOpt-AFL will execute the target program in the - core fuzzing module, then it will enter the PSO updating module. -'limit_time_bound': control how many interesting test cases need to be found - before MOpt-AFL quits the pacemaker fuzzing mode and reuses the deterministic stage. - 0 < 'limit_time_bound' < 1, MOpt-AFL-tmp. - 'limit_time_bound' >= 1, MOpt-AFL-ever. - -Have fun with MOpt in AFL! diff --git a/docs/historical_notes.md b/docs/historical_notes.md deleted file mode 100644 index b5d3d157..00000000 --- a/docs/historical_notes.md +++ /dev/null @@ -1,143 +0,0 @@ -# Historical notes - - This doc talks about the rationale of some of the high-level design decisions - for American Fuzzy Lop. It's adopted from a discussion with Rob Graham. - See README.md for the general instruction manual, and technical_details.md for - additional implementation-level insights. - -## 1) Influences - -In short, `afl-fuzz` is inspired chiefly by the work done by Tavis Ormandy back -in 2007. Tavis did some very persuasive experiments using `gcov` block coverage -to select optimal test cases out of a large corpus of data, and then using -them as a starting point for traditional fuzzing workflows. - -(By "persuasive", I mean: netting a significant number of interesting -vulnerabilities.) - -In parallel to this, both Tavis and I were interested in evolutionary fuzzing. -Tavis had his experiments, and I was working on a tool called bunny-the-fuzzer, -released somewhere in 2007. - -Bunny used a generational algorithm not much different from `afl-fuzz`, but -also tried to reason about the relationship between various input bits and -the internal state of the program, with hopes of deriving some additional value -from that. The reasoning / correlation part was probably in part inspired by -other projects done around the same time by Will Drewry and Chris Evans. - -The state correlation approach sounded very sexy on paper, but ultimately, made -the fuzzer complicated, brittle, and cumbersome to use; every other target -program would require a tweak or two. Because Bunny didn't fare a whole lot -better than less sophisticated brute-force tools, I eventually decided to write -it off. You can still find its original documentation at: - - https://code.google.com/p/bunny-the-fuzzer/wiki/BunnyDoc - -There has been a fair amount of independent work, too. Most notably, a few -weeks earlier that year, Jared DeMott had a Defcon presentation about a -coverage-driven fuzzer that relied on coverage as a fitness function. - -Jared's approach was by no means identical to what afl-fuzz does, but it was in -the same ballpark. His fuzzer tried to explicitly solve for the maximum coverage -with a single input file; in comparison, afl simply selects for cases that do -something new (which yields better results - see [technical_details.md](technical_details.md)). - -A few years later, Gabriel Campana released fuzzgrind, a tool that relied purely -on Valgrind and a constraint solver to maximize coverage without any brute-force -bits; and Microsoft Research folks talked extensively about their still -non-public, solver-based SAGE framework. - -In the past six years or so, I've also seen a fair number of academic papers -that dealt with smart fuzzing (focusing chiefly on symbolic execution) and a -couple papers that discussed proof-of-concept applications of genetic -algorithms with the same goals in mind. I'm unconvinced how practical most of -these experiments were; I suspect that many of them suffer from the -bunny-the-fuzzer's curse of being cool on paper and in carefully designed -experiments, but failing the ultimate test of being able to find new, -worthwhile security bugs in otherwise well-fuzzed, real-world software. - -In some ways, the baseline that the "cool" solutions have to compete against is -a lot more impressive than it may seem, making it difficult for competitors to -stand out. For a singular example, check out the work by Gynvael and Mateusz -Jurczyk, applying "dumb" fuzzing to ffmpeg, a prominent and security-critical -component of modern browsers and media players: - - http://googleonlinesecurity.blogspot.com/2014/01/ffmpeg-and-thousand-fixes.html - -Effortlessly getting comparable results with state-of-the-art symbolic execution -in equally complex software still seems fairly unlikely, and hasn't been -demonstrated in practice so far. - -But I digress; ultimately, attribution is hard, and glorying the fundamental -concepts behind AFL is probably a waste of time. The devil is very much in the -often-overlooked details, which brings us to... - -## 2. Design goals for afl-fuzz - -In short, I believe that the current implementation of afl-fuzz takes care of -several itches that seemed impossible to scratch with other tools: - -1) Speed. It's genuinely hard to compete with brute force when your "smart" - approach is resource-intensive. If your instrumentation makes it 10x more - likely to find a bug, but runs 100x slower, your users are getting a bad - deal. - - To avoid starting with a handicap, `afl-fuzz` is meant to let you fuzz most of - the intended targets at roughly their native speed - so even if it doesn't - add value, you do not lose much. - - On top of this, the tool leverages instrumentation to actually reduce the - amount of work in a couple of ways: for example, by carefully trimming the - corpus or skipping non-functional but non-trimmable regions in the input - files. - -2) Rock-solid reliability. It's hard to compete with brute force if your - approach is brittle and fails unexpectedly. Automated testing is attractive - because it's simple to use and scalable; anything that goes against these - principles is an unwelcome trade-off and means that your tool will be used - less often and with less consistent results. - - Most of the approaches based on symbolic execution, taint tracking, or - complex syntax-aware instrumentation are currently fairly unreliable with - real-world targets. Perhaps more importantly, their failure modes can render - them strictly worse than "dumb" tools, and such degradation can be difficult - for less experienced users to notice and correct. - - In contrast, `afl-fuzz` is designed to be rock solid, chiefly by keeping it - simple. In fact, at its core, it's designed to be just a very good - traditional fuzzer with a wide range of interesting, well-researched - strategies to go by. The fancy parts just help it focus the effort in - places where it matters the most. - -3) Simplicity. The author of a testing framework is probably the only person - who truly understands the impact of all the settings offered by the tool - - and who can dial them in just right. Yet, even the most rudimentary fuzzer - frameworks often come with countless knobs and fuzzing ratios that need to - be guessed by the operator ahead of the time. This can do more harm than - good. - - AFL is designed to avoid this as much as possible. The three knobs you - can play with are the output file, the memory limit, and the ability to - override the default, auto-calibrated timeout. The rest is just supposed to - work. When it doesn't, user-friendly error messages outline the probable - causes and workarounds, and get you back on track right away. - -4) Chainability. Most general-purpose fuzzers can't be easily employed - against resource-hungry or interaction-heavy tools, necessitating the - creation of custom in-process fuzzers or the investment of massive CPU - power (most of which is wasted on tasks not directly related to the code - we actually want to test). - - AFL tries to scratch this itch by allowing users to use more lightweight - targets (e.g., standalone image parsing libraries) to create small - corpora of interesting test cases that can be fed into a manual testing - process or a UI harness later on. - -As mentioned in [technical_details.md](technical_details.md), AFL does all this not by systematically -applying a single overarching CS concept, but by experimenting with a variety -of small, complementary methods that were shown to reliably yields results -better than chance. The use of instrumentation is a part of that toolkit, but is -far from being the most important one. - -Ultimately, what matters is that `afl-fuzz` is designed to find cool bugs - and -has a pretty robust track record of doing just that. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md deleted file mode 100644 index f55aeaf2..00000000 --- a/docs/notes_for_asan.md +++ /dev/null @@ -1,157 +0,0 @@ -# Notes for using ASAN with afl-fuzz - - This file discusses some of the caveats for fuzzing under ASAN, and suggests - a handful of alternatives. See README.md for the general instruction manual. - -## 1) Short version - -ASAN on 64-bit systems requests a lot of memory in a way that can't be easily -distinguished from a misbehaving program bent on crashing your system. - -Because of this, fuzzing with ASAN is recommended only in four scenarios: - - - On 32-bit systems, where we can always enforce a reasonable memory limit - (-m 800 or so is a good starting point), - - - On 64-bit systems only if you can do one of the following: - - - Compile the binary in 32-bit mode (gcc -m32), - - - Precisely gauge memory needs using http://jwilk.net/software/recidivm . - - - Limit the memory available to process using cgroups on Linux (see - utils/asan_cgroups). - -To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The -afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. -Note that ASAN is incompatible with -static, so be mindful of that. - -(You can also use AFL_USE_MSAN=1 to enable MSAN instead.) - -When compiling with AFL_USE_LSAN, the leak sanitizer will normally run -when the program exits. In order to utilize this check at different times, -such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();. -This macro will report a crash in afl-fuzz if any memory is left leaking -at this stage. You can also use LSAN_OPTIONS and a supressions file -for more fine-tuned checking, however make sure you keep exitcode=23. - -NOTE: if you run several secondary instances, only one should run the target -compiled with ASAN (and UBSAN, CFISAN), the others should run the target with -no sanitizers compiled in. - -There is also the option of generating a corpus using a non-ASAN binary, and -then feeding it to an ASAN-instrumented one to check for bugs. This is faster, -and can give you somewhat comparable results. You can also try using -libdislocator (see [utils/libdislocator/README.dislocator.md](../utils/libdislocator/README.dislocator.md) in the parent directory) as a -lightweight and hassle-free (but less thorough) alternative. - -## 2) Long version - -ASAN allocates a huge region of virtual address space for bookkeeping purposes. -Most of this is never actually accessed, so the OS never has to allocate any -real pages of memory for the process, and the VM grabbed by ASAN is essentially -"free" - but the mapping counts against the standard OS-enforced limit -(RLIMIT_AS, aka ulimit -v). - -On our end, afl-fuzz tries to protect you from processes that go off-rails -and start consuming all the available memory in a vain attempt to parse a -malformed input file. This happens surprisingly often, so enforcing such a limit -is important for almost any fuzzer: the alternative is for the kernel OOM -handler to step in and start killing random processes to free up resources. -Needless to say, that's not a very nice prospect to live with. - -Unfortunately, un*x systems offer no portable way to limit the amount of -pages actually given to a process in a way that distinguishes between that -and the harmless "land grab" done by ASAN. In principle, there are three standard -ways to limit the size of the heap: - - - The RLIMIT_AS mechanism (ulimit -v) caps the size of the virtual space - - but as noted, this pays no attention to the number of pages actually - in use by the process, and doesn't help us here. - - - The RLIMIT_DATA mechanism (ulimit -d) seems like a good fit, but it applies - only to the traditional sbrk() / brk() methods of requesting heap space; - modern allocators, including the one in glibc, routinely rely on mmap() - instead, and circumvent this limit completely. - - - Finally, the RLIMIT_RSS limit (ulimit -m) sounds like what we need, but - doesn't work on Linux - mostly because nobody felt like implementing it. - -There are also cgroups, but they are Linux-specific, not universally available -even on Linux systems, and they require root permissions to set up; I'm a bit -hesitant to make afl-fuzz require root permissions just for that. That said, -if you are on Linux and want to use cgroups, check out the contributed script -that ships in utils/asan_cgroups/. - -In settings where cgroups aren't available, we have no nice, portable way to -avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for -binaries compiled in 32-bit mode (-m32), this is not a big deal: ASAN needs -around 600-800 MB or so, depending on the compiler - so all you need to do is -to specify -m that is a bit higher than that. - -On 64-bit systems, the situation is more murky, because the ASAN allocation -is completely outlandish - around 17.5 TB in older versions, and closer to -20 TB with newest ones. The actual amount of memory on your system is -(probably!) just a tiny fraction of that - so unless you dial the limit -with surgical precision, you will get no protection from OOM bugs. - -On my system, the amount of memory grabbed by ASAN with a slightly older -version of gcc is around 17,825,850 MB; for newest clang, it's 20,971,600. -But there is no guarantee that these numbers are stable, and if you get them -wrong by "just" a couple gigs or so, you will be at risk. - -To get the precise number, you can use the recidivm tool developed by Jakub -Wilk (http://jwilk.net/software/recidivm). In absence of this, ASAN is *not* -recommended when fuzzing 64-bit binaries, unless you are confident that they -are robust and enforce reasonable memory limits (in which case, you can -specify '-m none' when calling afl-fuzz). - -Using recidivm or running with no limits aside, there are two other decent -alternatives: build a corpus of test cases using a non-ASAN binary, and then -examine them with ASAN, Valgrind, or other heavy-duty tools in a more -controlled setting; or compile the target program with -m32 (32-bit mode) -if your system supports that. - -## 3) Interactions with the QEMU mode - -ASAN, MSAN, and other sanitizers appear to be incompatible with QEMU user -emulation, so please do not try to use them with the -Q option; QEMU doesn't -seem to appreciate the shadow VM trick used by these tools, and will likely -just allocate all your physical memory, then crash. - -You can, however, use QASan to run binaries that are not instrumented with ASan -under QEMU with the AFL++ instrumentation. - -https://github.com/andreafioraldi/qasan - -## 4) ASAN and OOM crashes - -By default, ASAN treats memory allocation failures as fatal errors, immediately -causing the program to crash. Since this is a departure from normal POSIX -semantics (and creates the appearance of security issues in otherwise -properly-behaving programs), we try to disable this by specifying -allocator_may_return_null=1 in ASAN_OPTIONS. - -Unfortunately, it's been reported that this setting still causes ASAN to -trigger phantom crashes in situations where the standard allocator would -simply return NULL. If this is interfering with your fuzzing jobs, you may -want to cc: yourself on this bug: - - https://bugs.llvm.org/show_bug.cgi?id=22026 - -## 5) What about UBSAN? - -New versions of UndefinedBehaviorSanitizer offers the --fsanitize=undefined-trap-on-error compiler flag that tells UBSan to insert an -istruction that will cause SIGILL (ud2 on x86) when an undefined behaviour -is detected. This is the option that you want to use when combining AFL++ -and UBSan. - -AFL_USE_UBSAN=1 env var will add this compiler flag to afl-clang-fast, -afl-gcc-fast and afl-gcc for you. - -Old versions of UBSAN don't offer a consistent way -to abort() on fault conditions or to terminate with a distinctive exit code -but there are some versions of the library can be binary-patched to address this -issue. You can also preload a shared library that substitute all the UBSan -routines used to report errors with abort(). diff --git a/docs/perf_tips.md b/docs/perf_tips.md index c5968206..7c14cbbc 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -48,13 +48,9 @@ be then manually fed to a more resource-hungry program later on. Also note that reading the fuzzing input via stdin is faster than reading from a file. -## 3. Use LLVM instrumentation +## 3. Use LLVM persistent instrumentation -When fuzzing slow targets, you can gain 20-100% performance improvement by -using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md). -Note that this mode requires the use of clang and will not work with GCC. - -The LLVM mode also offers a "persistent", in-process fuzzing mode that can +The LLVM mode offers a "persistent", in-process fuzzing mode that can work well for certain types of self-contained libraries, and for fast targets, can offer performance gains up to 5-10x; and a "deferred fork server" mode that can offer huge benefits for programs with high startup overhead. Both @@ -138,8 +134,7 @@ misses, or similar factors, but they are less likely to be a concern.) ## 7. Keep memory use and timeouts in check -If you have increased the `-m` or `-t` limits more than truly necessary, consider -dialing them back down. +Consider setting low values for -m and -t. For programs that are nominally very fast, but get sluggish for some inputs, you can also try setting `-t` values that are more punishing than what `afl-fuzz` @@ -164,6 +159,20 @@ There are several OS-level factors that may affect fuzzing speed: - Network filesystems, either used for fuzzer input / output, or accessed by the fuzzed binary to read configuration files (pay special attention to the home directory - many programs search it for dot-files). + - Disable all the spectre, meltdown etc. security countermeasures in the + kernel if your machine is properly separated: + +``` +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 +``` + In most Linux distributions you can put this into a `/etc/default/grub` + variable. + +The following list of changes are made when executing `afl-system-config`: + - On-demand CPU scaling. The Linux `ondemand` governor performs its analysis on a particular schedule and is known to underestimate the needs of short-lived processes spawned by `afl-fuzz` (or any other fuzzer). On Linux, @@ -196,26 +205,4 @@ There are several OS-level factors that may affect fuzzing speed: Setting a different scheduling policy for the fuzzer process - say `SCHED_RR` - can usually speed things up, too, but needs to be done with care. - - Use the `afl-system-config` script to set all proc/sys settings above in one go. - - Disable all the spectre, meltdown etc. security countermeasures in the - kernel if your machine is properly separated: - -``` -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 -``` - In most Linux distributions you can put this into a `/etc/default/grub` - variable. - -## 9. If all other options fail, use `-d` - -For programs that are genuinely slow, in cases where you really can't escape -using huge input files, or when you simply want to get quick and dirty results -early on, you can always resort to the `-d` mode. -The mode causes `afl-fuzz` to skip all the deterministic fuzzing steps, which -makes output a lot less neat and can ultimately make the testing a bit less -in-depth, but it will give you an experience more familiar from other fuzzing -tools. diff --git a/docs/power_schedules.md b/docs/power_schedules.md deleted file mode 100644 index 493f9609..00000000 --- a/docs/power_schedules.md +++ /dev/null @@ -1,32 +0,0 @@ -# afl++'s power schedules based on AFLfast - - -Power schedules implemented by Marcel Böhme \. -AFLFast is an extension of AFL which is written and maintained by -Michal Zalewski \. - -AFLfast has helped in the success of Team Codejitsu at the finals of the DARPA Cyber Grand Challenge where their bot Galactica took **2nd place** in terms of #POVs proven (see red bar at https://www.cybergrandchallenge.com/event#results). AFLFast exposed several previously unreported CVEs that could not be exposed by AFL in 24 hours and otherwise exposed vulnerabilities significantly faster than AFL while generating orders of magnitude more unique crashes. - -Essentially, we observed that most generated inputs exercise the same few "high-frequency" paths and developed strategies to gravitate towards low-frequency paths, to stress significantly more program behavior in the same amount of time. We devised several **search strategies** that decide in which order the seeds should be fuzzed and **power schedules** that smartly regulate the number of inputs generated from a seed (i.e., the time spent fuzzing a seed). We call the number of inputs generated from a seed, the seed's **energy**. - -We find that AFL's exploitation-based constant schedule assigns **too much energy to seeds exercising high-frequency paths** (e.g., paths that reject invalid inputs) and not enough energy to seeds exercising low-frequency paths (e.g., paths that stress interesting behaviors). Technically, we modified the computation of a seed's performance score (`calculate_score`), which seed is marked as favourite (`update_bitmap_score`), and which seed is chosen next from the circular queue (`main`). We implemented the following schedules (in the order of their effectiveness, best first): - -| AFL flag | Power Schedule | -| ------------- | -------------------------- | -| `-p explore` | ![EXPLORE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D) | -| `-p fast` (default)| ![FAST](http://latex.codecogs.com/gif.latex?p(i)=\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) | -| `-p coe` | ![COE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cbegin%7Bcases%7D%200%20%26%20%5Ctext%7B%20if%20%7D%20f%28i%29%20%3E%20%5Cmu%5C%5C%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%202%5E%7Bs%28i%29%7D%2C%20M%5Cright%29%20%26%20%5Ctext%7B%20otherwise.%7D%20%5Cend%7Bcases%7D) | -| `-p quad` | ![QUAD](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%5E2%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p lin` | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p exploit` (AFL) | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Calpha%28i%29) | -| `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries | -| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges | -| `-p seek` | Experimental: `seek` is EXPLORE but ignoring the runtime of the queue input and less focus on the size | -where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path. - -More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/). - -PS: In parallel mode (several instances with shared queue), we suggest to run the main node using the exploit schedule (-p exploit) and the secondary nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast; default), and explore (-p explore) schedules. In single mode, the default settings will do. **EDIT:** In parallel mode, AFLFast seems to perform poorly because the path probability estimates are incorrect for the imported seeds. Pull requests to fix this issue by syncing the estimates across instances are appreciated :) - -Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. -Released under terms and conditions of Apache License, Version 2.0. diff --git a/docs/technical_details.md b/docs/technical_details.md index a0453c91..6a4660a2 100644 --- a/docs/technical_details.md +++ b/docs/technical_details.md @@ -1,5 +1,9 @@ # Technical "whitepaper" for afl-fuzz + +NOTE: this document is rather outdated! + + This document provides a quick overview of the guts of American Fuzzy Lop. See README.md for the general instruction manual; and for a discussion of motivations and design goals behind AFL, see historical_notes.md. diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 3f518b55..b01ea987 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -299,8 +299,9 @@ static void __afl_map_shm(void) { if (!getenv("AFL_QUIET")) fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u " - "to be able to run this instrumented program!\n", + "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u " + "to be able to run this instrumented program if this " + "crashes!\n", __afl_final_loc); } -- cgit 1.4.1 From 4fe572b80f76ff0b0e916b639d1e04d5af48b157 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 12:24:29 +0200 Subject: always build aflpp driver --- GNUmakefile | 3 +-- docs/Changelog.md | 1 + utils/aflpp_driver/GNUmakefile | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index 53cc0537..7a1ba88a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -306,6 +306,7 @@ endif .PHONY: all all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done + -$(MAKE) -C utils/aflpp_driver .PHONY: llvm llvm: @@ -597,7 +598,6 @@ distrib: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C utils/libdislocator $(MAKE) -C utils/libtokencap - -$(MAKE) -C utils/aflpp_driver $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing @@ -622,7 +622,6 @@ source-only: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C utils/libdislocator $(MAKE) -C utils/libtokencap - -$(MAKE) -C utils/aflpp_driver %.8: % @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ diff --git a/docs/Changelog.md b/docs/Changelog.md index 705daa40..29af44ab 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -36,6 +36,7 @@ sending a mail to . - fix timeout handling - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module + - always build aflpp_driver for libfuzzer harnesses - added `AFL_NO_FORKSRV` env variable support to afl-cmin, afl-tmin, and afl-showmap, by @jhertz - removed outdated documents, improved existing documentation diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index ad99b893..c282a9f3 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -15,28 +15,28 @@ aflpp_driver.o: aflpp_driver.c -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c libAFLDriver.a: aflpp_driver.o - ar ru libAFLDriver.a aflpp_driver.o - cp -vf libAFLDriver.a ../../ + @ar rc libAFLDriver.a aflpp_driver.o + @cp -vf libAFLDriver.a ../../ debug: $(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c - ar ru libAFLDriver.a afl-performance.o aflpp_driver.o + ar rc libAFLDriver.a afl-performance.o aflpp_driver.o aflpp_qemu_driver.o: aflpp_qemu_driver.c -$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c libAFLQemuDriver.a: aflpp_qemu_driver.o - -ar ru libAFLQemuDriver.a aflpp_qemu_driver.o - -cp -vf libAFLQemuDriver.a ../../ + @-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o + @-cp -vf libAFLQemuDriver.a ../../ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - -test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." + @-test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." + @-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c -- cgit 1.4.1 From 9ec63d3f1776ae1442fe89d5e076b58b36997f76 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 14:31:27 +0200 Subject: fix frida, fix dictionary generation to honor AFL_LLVM_{ALLOW/DENY}LIST --- docs/Changelog.md | 2 ++ frida_mode/src/instrument/instrument.c | 3 ++- instrumentation/SanitizerCoverageLTO.so.cc | 2 ++ instrumentation/afl-llvm-dict2file.so.cc | 1 + instrumentation/afl-llvm-pass.so.cc | 4 ++-- 5 files changed, 9 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29af44ab..8aca5608 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -24,10 +24,12 @@ sending a mail to . - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking + - do honor AFL_LLVM_{ALLOW/DENY}LIST for LTO autodictionary and DICT2FILE - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - less coverage collision - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) - afl-cmin and afl-showmap -i do now descend into subdirectories diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 81d14013..e1dabf92 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "frida-gumjs.h" @@ -289,7 +290,7 @@ void instrument_init(void) { * needs to be different for each instance. */ instrument_hash_seed = - g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ gettid(); + g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ syscall(SYS_gettid); OKF("Instrumentation - seed [0x%016" G_GINT64_MODIFIER "x]", instrument_hash_seed); diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 28eb0b9f..91b81910 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -516,6 +516,8 @@ bool ModuleSanitizerCoverage::instrumentModule( for (auto &F : M) { + if (!isInInstrumentList(&F) || !F.size()) { continue; } + for (auto &BB : F) { for (auto &IN : BB) { diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 5350f62b..9daa75a8 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -154,6 +154,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { for (auto &F : M) { if (isIgnoreFunction(&F)) continue; + if (!isInInstrumentList(&F) || !F.size()) { continue; } /* Some implementation notes. * diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 94b77f7d..ecf28f31 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -438,9 +438,9 @@ bool AFLCoverage::runOnModule(Module &M) { fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(), F.size()); - if (!isInInstrumentList(&F)) continue; + if (!isInInstrumentList(&F)) { continue; } - if (F.size() < function_minimum_size) continue; + if (F.size() < function_minimum_size) { continue; } std::list todo; for (auto &BB : F) { -- cgit 1.4.1 From 8a2b140f406acc44bfa48574eb0440cfc92b462f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Jul 2021 12:42:57 +0200 Subject: nits --- docs/perf_tips.md | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/perf_tips.md b/docs/perf_tips.md index 7c14cbbc..9c31e56b 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -134,7 +134,7 @@ misses, or similar factors, but they are less likely to be a concern.) ## 7. Keep memory use and timeouts in check -Consider setting low values for -m and -t. +Consider setting low values for `-m` and `-t`. For programs that are nominally very fast, but get sluggish for some inputs, you can also try setting `-t` values that are more punishing than what `afl-fuzz` diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 0d82727f..019b8715 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 0d82727f2b477de82fa355edef9bc158bd25d374 +Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad -- cgit 1.4.1 From 6f03749c734e535cf9488027c692a7ee2591b60f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Jul 2021 16:27:40 +0200 Subject: ammend changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 8aca5608..7131360a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,11 +12,13 @@ sending a mail to . - afl-fuzz: - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs + - fix for AFLfast schedule counting - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - reverse read the queue on resumes (more effective) + - fix custom mutator trimming - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! -- cgit 1.4.1 From 18fd97fc5ffc5ad94e735cfbfa0d500463dcb585 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 19 Jul 2021 09:12:24 +0200 Subject: v3.14c release --- README.md | 9 +++++++-- docs/Changelog.md | 2 +- utils/qbdi_mode/README.md | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/README.md b/README.md index 37fd90e3..94a38ab1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AFL++ Logo - Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [3.14c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.14a + Github Version: 3.15a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) @@ -31,6 +31,11 @@ With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android, iOS etc. +With afl++ 3.15 we introduced the following changes from previous behaviours: + * Also -M main mode does not due deterministic fuzzing by default anymore + * afl-cmin and afl-showmap -Ci now descent into subdirectories like + afl-fuzz -i does (but note that afl-cmin.bash does not) + With afl++ 3.14 we introduced the following changes from previous behaviours: * afl-fuzz: deterministic fuzzing it not a default for -M main anymore * afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash diff --git a/docs/Changelog.md b/docs/Changelog.md index 7131360a..fcfd2ce8 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,7 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++3.14a (release) +### Version ++3.14c (release) - afl-fuzz: - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index 641a6e85..cf5d3359 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -1,5 +1,9 @@ # qbdi-based binary-only instrumentation for afl-fuzz +NOTE: this code is outdated and first would need to be adapted to the current +afl++ versions first. +Try afl_frida or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. + ## 1) Introduction The code in ./qbdi_mode allows you to build a standalone feature that -- cgit 1.4.1