From 62f1bfed99b82bc073c138a00ff9a30bb596d09d Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Tue, 20 Jul 2021 04:23:26 +0000 Subject: utils: added optimin corpus minimizer --- utils/README.md | 2 + utils/optimin/.gitignore | 11 + utils/optimin/CMakeLists.txt | 22 ++ utils/optimin/EVALMAXSAT_VERSION | 1 + utils/optimin/EvalMaxSAT | 1 + utils/optimin/README.md | 74 +++++++ utils/optimin/build_optimin.sh | 130 +++++++++++ utils/optimin/src/CMakeLists.txt | 12 ++ utils/optimin/src/OptiMin.cpp | 455 +++++++++++++++++++++++++++++++++++++++ utils/optimin/src/ProgressBar.h | 58 +++++ 10 files changed, 766 insertions(+) create mode 100644 utils/optimin/.gitignore create mode 100644 utils/optimin/CMakeLists.txt create mode 100644 utils/optimin/EVALMAXSAT_VERSION create mode 160000 utils/optimin/EvalMaxSAT create mode 100644 utils/optimin/README.md create mode 100755 utils/optimin/build_optimin.sh create mode 100644 utils/optimin/src/CMakeLists.txt create mode 100644 utils/optimin/src/OptiMin.cpp create mode 100644 utils/optimin/src/ProgressBar.h (limited to 'utils') diff --git a/utils/README.md b/utils/README.md index b157424f..92619fd0 100644 --- a/utils/README.md +++ b/utils/README.md @@ -40,6 +40,8 @@ Here's a quick overview of the stuff you can find in this directory: - libpng_no_checksum - a sample patch for removing CRC checks in libpng. + - optimin - An optimal corpus minimizer. + - persistent_mode - an example of how to use the LLVM persistent process mode to speed up certain fuzzing jobs. diff --git a/utils/optimin/.gitignore b/utils/optimin/.gitignore new file mode 100644 index 00000000..46f42f8f --- /dev/null +++ b/utils/optimin/.gitignore @@ -0,0 +1,11 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps diff --git a/utils/optimin/CMakeLists.txt b/utils/optimin/CMakeLists.txt new file mode 100644 index 00000000..b45dd004 --- /dev/null +++ b/utils/optimin/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) + +project(optimin + LANGUAGES CXX + DESCRIPTION "MaxSAT-based fuzzing corpus minimizer" +) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + +# Add LLVM +find_package(LLVM REQUIRED CONFIG) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS} -DNDEBUG) + +add_subdirectory(EvalMaxSAT) +add_subdirectory(src) diff --git a/utils/optimin/EVALMAXSAT_VERSION b/utils/optimin/EVALMAXSAT_VERSION new file mode 100644 index 00000000..d836ff1c --- /dev/null +++ b/utils/optimin/EVALMAXSAT_VERSION @@ -0,0 +1 @@ +440bf90edf88f6ab940934129e3c5b3b93764295 diff --git a/utils/optimin/EvalMaxSAT b/utils/optimin/EvalMaxSAT new file mode 160000 index 00000000..440bf90e --- /dev/null +++ b/utils/optimin/EvalMaxSAT @@ -0,0 +1 @@ +Subproject commit 440bf90edf88f6ab940934129e3c5b3b93764295 diff --git a/utils/optimin/README.md b/utils/optimin/README.md new file mode 100644 index 00000000..5001b59d --- /dev/null +++ b/utils/optimin/README.md @@ -0,0 +1,74 @@ +# OptiMin + +OptiMin is a corpus minimizer that uses a +[MaxSAT](https://en.wikipedia.org/wiki/Maximum_satisfiability_problem) solver +to identify a subset of functionally distinct files that exercise different code +paths in a target program. + +Unlike most corpus minimizers, such as `afl-cmin`, OptiMin does not rely on +heuristic and/or greedy algorithms to identify these functionally distinct +files. This means that minimized corpora are generally much smaller than those +produced by other tools. + +## Usage + +To build the `optimin` executable (when cloned from github): + +```bash +# Ensure EvalMaxSAT is available +git submodule init +git submodule update + +mkdir build +cd build + +# You may have to specify -DLLVM_DIR=`llvm-config --cmakedir` if you have a +# non-standard LLVM install (e.g., install via apt) +cmake .. +make -j +make install +``` + +Otherwise, run the `build_optimin.sh` script. Running `optimin` is the same as +running `afl-cmin`. + +### Weighted Minimizations + +OptiMin allows for weighted minimizations. For examples, seeds can be weighted +by file size (or execution time), thus preferencing the selection of smaller (or +faster) seeds. + +To perform a weighted minimization, supply a CSV file with the `-w` option. This +CSV file is formatted as follows: + +``` +SEED_1,WEIGHT_1 +SEED_2,WEIGHT_2 +... +SEED_N,WEIGHT_N +``` + +Where `SEED_N` is the file name (**not** path) of a seed in the input directory, +and `WEIGHT_N` is an integer weight. + +## Further Details and Citation + +For more details, please see the paper [Seed Selection for Successful +Fuzzing](https://dl.acm.org/doi/10.1145/3460319.3464795). If you use OptiMin in +your research, please cite this paper. + +Bibtex: + +```bibtex +@inproceedings{Herrera:2021:FuzzSeedSelection, + author = {Adrian Herrera and Hendra Gunadi and Shane Magrath and Michael Norrish and Mathias Payer and Antony L. Hosking}, + title = {Seed Selection for Successful Fuzzing}, + booktitle = {30th ACM SIGSOFT International Symposium on Software Testing and Analysis}, + series = {ISSTA}, + year = {2021}, + pages = {230--243}, + numpages = {14}, + location = {Virtual, Denmark}, + publisher = {Association for Computing Machinery}, +} +``` diff --git a/utils/optimin/build_optimin.sh b/utils/optimin/build_optimin.sh new file mode 100755 index 00000000..7397aa45 --- /dev/null +++ b/utils/optimin/build_optimin.sh @@ -0,0 +1,130 @@ +#!/bin/sh +# +# american fuzzy lop++ - optimin build script +# ------------------------------------------------ +# +# Originally written by Nathan Voss +# +# Adapted from code by Andrew Griffiths and +# Michal Zalewski +# +# Adapted for AFLplusplus by Dominik Maier +# +# Copyright 2017 Battelle Memorial Institute. 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 +# +# This script builds the OptiMin corpus minimizer. + +EVALMAXSAT_VERSION="$(cat ./EVALMAXSAT_VERSION)" +EVALMAXSAT_REPO="https://github.com/FlorentAvellaneda/EvalMaxSAT" + +echo "=================================================" +echo "OptiMin build script" +echo "=================================================" +echo + +echo "[*] Performing basic sanity checks..." + +PLT=`uname -s` + +if [ ! -f "../../config.h" ]; then + + echo "[-] Error: key files not found - wrong working directory?" + exit 1 + +fi + +LLVM_CONFIG="${LLVM_CONFIG:-llvm-config}" +CMAKECMD=cmake +MAKECMD=make +TARCMD=tar + +if [ "$PLT" = "Darwin" ]; then + CORES=`sysctl -n hw.ncpu` + TARCMD=tar +fi + +if [ "$PLT" = "FreeBSD" ]; then + MAKECMD=gmake + CORES=`sysctl -n hw.ncpu` + TARCMD=gtar +fi + +if [ "$PLT" = "NetBSD" ] || [ "$PLT" = "OpenBSD" ]; then + MAKECMD=gmake + CORES=`sysctl -n hw.ncpu` + TARCMD=gtar +fi + +PREREQ_NOTFOUND= +for i in git $CMAKECMD $MAKECMD $TARCMD; do + + T=`command -v "$i" 2>/dev/null` + + if [ "$T" = "" ]; then + + echo "[-] Error: '$i' not found. Run 'sudo apt-get install $i' or similar." + PREREQ_NOTFOUND=1 + + fi + +done + +if echo "$CC" | grep -qF /afl-; then + + echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool." + PREREQ_NOTFOUND=1 + +fi + +if [ "$PREREQ_NOTFOUND" = "1" ]; then + exit 1 +fi + +echo "[+] All checks passed!" + +echo "[*] Making sure EvalMaxSAT is checked out" + +git status 1>/dev/null 2>/dev/null +if [ $? -eq 0 ]; then + echo "[*] initializing EvalMaxSAT submodule" + git submodule init || exit 1 + git submodule update ./EvalMaxSAT 2>/dev/null # ignore errors +else + echo "[*] cloning EvalMaxSAT" + test -d EvalMaxSAT || { + CNT=1 + while [ '!' -d EvalMaxSAT -a "$CNT" -lt 4 ]; do + echo "Trying to clone EvalMaxSAT (attempt $CNT/3)" + git clone "$GRAMMAR_REPO" + CNT=`expr "$CNT" + 1` + done + } +fi + +test -d EvalMaxSAT || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; } +echo "[+] Got EvalMaxSAT." + +cd "EvalMaxSAT" || exit 1 +echo "[*] Checking out $EVALMAXSAT_VERSION" +sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null +git checkout "$EVALMAXSAT_VERSION" || exit 1 +cd .. + +echo +echo +echo "[+] EvalMaxSAT successfully prepared!" +echo "[+] Building OptiMin now." +mkdir -p build +cd build +cmake .. -DLLVM_DIR=`$LLVM_CONFIG --cmakedir` +make -j$CORES +cd .. +echo +echo "[+] OptiMin successfully built!" diff --git a/utils/optimin/src/CMakeLists.txt b/utils/optimin/src/CMakeLists.txt new file mode 100644 index 00000000..f31ceeaf --- /dev/null +++ b/utils/optimin/src/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(optimin OptiMin.cpp) + +foreach(LIB MaLib EvalMaxSAT glucose) + target_include_directories(optimin PRIVATE + "${CMAKE_SOURCE_DIR}/EvalMaxSAT/lib/${LIB}/src") + target_link_libraries(optimin ${LIB}) +endforeach(LIB) + +llvm_map_components_to_libnames(LLVM_LIBS support) +target_link_libraries(optimin ${LLVM_LIBS}) + +install(TARGETS optimin RUNTIME DESTINATION bin) diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp new file mode 100644 index 00000000..e02fcbe5 --- /dev/null +++ b/utils/optimin/src/OptiMin.cpp @@ -0,0 +1,455 @@ +/* + * OptiMin, an optimal fuzzing corpus minimizer. + * + * Author: Adrian Herrera + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "EvalMaxSAT.h" +#include "ProgressBar.h" + +using namespace llvm; + +namespace { + +// -------------------------------------------------------------------------- // +// Classes +// -------------------------------------------------------------------------- // + +/// Ensure seed weights default to 1 +class Weight { + public: + Weight() : Weight(1){}; + Weight(uint32_t V) : Value(V){}; + + operator unsigned() const { + return Value; + } + + private: + const unsigned Value; +}; + +// -------------------------------------------------------------------------- // +// Typedefs +// -------------------------------------------------------------------------- // + +/// AFL tuple (edge) ID +using AFLTupleID = uint32_t; + +/// Pair of tuple ID and hit count +using AFLTuple = std::pair; + +/// Coverage for a given seed file +using AFLCoverageVector = std::vector; + +/// Maps seed file paths to a weight +using WeightsMap = StringMap; + +/// A seed identifier in the MaxSAT solver +using SeedID = int; + +/// Associates seed identifiers to seed files +using MaxSATSeeds = + SmallVector, 0>; + +/// Set of literal identifiers +using MaxSATSeedSet = DenseSet; + +/// Maps tuple IDs to the literal identifiers that "cover" that tuple +using MaxSATCoverageMap = DenseMap; + +// -------------------------------------------------------------------------- // +// Global variables +// -------------------------------------------------------------------------- // + +// This is based on the human class count in `count_class_human[256]` in +// `afl-showmap.c` +static constexpr uint32_t MAX_EDGE_FREQ = 8; + +static sys::TimePoint<> StartTime, EndTime; +static std::chrono::seconds Duration; + +static std::string AFLShowmapPath; +static bool TargetArgsHasAtAt = false; + +static const auto ErrMsg = [] { + return WithColor(errs(), HighlightColor::Error) << "[-] "; +}; +static const auto WarnMsg = [] { + return WithColor(errs(), HighlightColor::Warning) << "[-] "; +}; +static const auto SuccMsg = [] { + return WithColor(outs(), HighlightColor::String) << "[+] "; +}; +static const auto StatMsg = [] { + return WithColor(outs(), HighlightColor::Remark) << "[*] "; +}; + +static cl::opt CorpusDir("i", cl::desc("Input directory"), + cl::value_desc("dir"), cl::Required); +static cl::opt OutputDir("o", cl::desc("Output directory"), + cl::value_desc("dir"), cl::Required); +static cl::opt EdgesOnly("f", cl::desc("Include edge hit counts"), + cl::init(true)); +static cl::opt ShowProgBar("p", cl::desc("Display progress bar")); +static cl::opt WeightsFile("w", cl::desc("Weights file"), + cl::value_desc("csv")); +static cl::opt TargetProg(cl::Positional, + cl::desc(""), + cl::Required); +static cl::list TargetArgs(cl::ConsumeAfter, + cl::desc("[target args...]")); +static cl::opt MemLimit( + "m", cl::desc("Memory limit for child process (default=none)"), + cl::value_desc("megs"), cl::init("none")); +static cl::opt Timeout( + "t", cl::desc("Run time limit for child process (default=none)"), + cl::value_desc("msec"), cl::init("none")); +static cl::opt CrashMode( + "C", cl::desc("Keep crashing inputs, reject everything else")); +static cl::opt QemuMode("Q", cl::desc("Use binary-only instrumentation")); +} // anonymous namespace + +// -------------------------------------------------------------------------- // +// Helper functions +// -------------------------------------------------------------------------- // + +static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { + SmallVector Lines; + MB.getBuffer().trim().split(Lines, '\n'); + + unsigned Weight = 0; + + for (const auto &Line : Lines) { + const auto &[Seed, WeightStr] = Line.split(','); + + if (to_integer(WeightStr, Weight, 10)) { + Weights.try_emplace(Seed, Weight); + } else { + WarnMsg() << "Failed to read weight for `" << Seed << "`. Skipping...\n"; + } + } +} + +[[nodiscard]] static std::error_code getAFLCoverage(const StringRef Seed, + AFLCoverageVector &Cov) { + Optional Redirects[] = {None, None, None}; + std::error_code EC; + + // Create temporary output file + SmallString<64> OutputPath; + if (EC = sys::fs::createTemporaryFile("showmap", "txt", OutputPath)) + return EC; + + // Prepare afl-showmap arguments + SmallVector AFLShowmapArgs{ + AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", OutputPath}; + + if (TargetArgsHasAtAt) + AFLShowmapArgs.append({"-A", Seed}); + else + Redirects[/* stdin */ 0] = Seed; + + if (QemuMode) AFLShowmapArgs.push_back("-Q"); + if (CrashMode) AFLShowmapArgs.push_back("-C"); + + AFLShowmapArgs.append({"--", TargetProg}); + AFLShowmapArgs.append(TargetArgs.begin(), TargetArgs.end()); + + // Run afl-showmap + const int RC = sys::ExecuteAndWait(AFLShowmapPath, AFLShowmapArgs, + /*env=*/None, Redirects); + if (RC) return std::make_error_code(std::errc::executable_format_error); + + // Parse afl-showmap output + const auto CovOrErr = MemoryBuffer::getFile(OutputPath); + if (EC = CovOrErr.getError()) { + sys::fs::remove(OutputPath); + return EC; + } + + SmallVector Lines; + CovOrErr.get()->getBuffer().trim().split(Lines, '\n'); + + AFLTupleID Edge = 0; + unsigned Freq = 0; + + for (const auto &Line : Lines) { + const auto &[EdgeStr, FreqStr] = Line.split(':'); + + to_integer(EdgeStr, Edge, 10); + to_integer(FreqStr, Freq, 10); + Cov.push_back({Edge, Freq}); + } + + return sys::fs::remove(OutputPath); +} + +static inline void StartTimer(bool ShowProgBar) { + StartTime = std::chrono::system_clock::now(); +} + +static inline void EndTimer(bool ShowProgBar) { + EndTime = std::chrono::system_clock::now(); + Duration = + std::chrono::duration_cast(EndTime - StartTime); + + if (ShowProgBar) + outs() << '\n'; + else + outs() << Duration.count() << "s\n"; +} + +// -------------------------------------------------------------------------- // +// Main function +// -------------------------------------------------------------------------- // + +int main(int argc, char *argv[]) { + WeightsMap Weights; + ProgressBar ProgBar; + std::error_code EC; + + // ------------------------------------------------------------------------ // + // Parse command-line options + // + // Also check the target arguments, as this determines how we run afl-showmap. + // ------------------------------------------------------------------------ // + + cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); + + if (!sys::fs::is_directory(OutputDir)) { + ErrMsg() << "Invalid output directory `" << OutputDir << "`\n"; + return 1; + } + + for (const auto &Arg : TargetArgs) + if (Arg == "@@") TargetArgsHasAtAt = true; + + // ------------------------------------------------------------------------ // + // Find afl-showmap + // ------------------------------------------------------------------------ // + + const auto AFLShowmapOrErr = sys::findProgramByName("afl-showmap"); + if (AFLShowmapOrErr.getError()) { + ErrMsg() << "Failed to find afl-showmap. Check your PATH\n"; + return 1; + } + AFLShowmapPath = *AFLShowmapOrErr; + + // ------------------------------------------------------------------------ // + // Parse weights + // + // Weights are stored in CSV file mapping a seed file name to an integer + // greater than zero. + // ------------------------------------------------------------------------ // + + if (WeightsFile != "") { + StatMsg() << "Reading weights from `" << WeightsFile << "`... "; + StartTimer(/*ShowProgBar=*/false); + + const auto WeightsOrErr = MemoryBuffer::getFile(WeightsFile); + if (EC = WeightsOrErr.getError()) { + ErrMsg() << "Failed to read weights from `" << WeightsFile + << "`: " << EC.message() << '\n'; + return 1; + } + + GetWeights(*WeightsOrErr.get(), Weights); + + EndTimer(/*ShowProgBar=*/false); + } + + // ------------------------------------------------------------------------ // + // Traverse corpus directory + // + // Find the seed files inside this directory. + // ------------------------------------------------------------------------ // + + StatMsg() << "Locating seeds in `" << CorpusDir << "`... "; + StartTimer(/*ShowProgBar=*/false); + + std::vector SeedFiles; + sys::fs::file_status Status; + + for (sys::fs::directory_iterator Dir(CorpusDir, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + if (EC) { + ErrMsg() << "Failed to traverse corpus directory `" << CorpusDir + << "`: " << EC.message() << '\n'; + return 1; + } + + const auto &Path = Dir->path(); + if (EC = sys::fs::status(Path, Status)) { + WarnMsg() << "Failed to access seed file `" << Path + << "`: " << EC.message() << ". Skipping...\n"; + continue; + } + + switch (Status.type()) { + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + SeedFiles.push_back(Path); + default: + /* Ignore */ + break; + } + } + + EndTimer(/*ShowProgBar=*/false); + + // ------------------------------------------------------------------------ // + // Generate seed coverage + // + // Iterate over the corpus directory, which should contain seed files. Execute + // these seeds in the target program to generate coverage information, and + // then store this coverage information in the appropriate data structures. + // ------------------------------------------------------------------------ // + + size_t SeedCount = 0; + const size_t NumSeeds = SeedFiles.size(); + + if (!ShowProgBar) + StatMsg() << "Generating coverage for " << NumSeeds << " seeds... "; + StartTimer(ShowProgBar); + + EvalMaxSAT Solver(/*nbMinimizeThread=*/0); + MaxSATSeeds SeedVars; + MaxSATCoverageMap SeedCoverage; + AFLCoverageVector Cov; + + for (const auto &SeedFile : SeedFiles) { + // Execute seed + Cov.clear(); + if (EC = getAFLCoverage(SeedFile, Cov)) { + ErrMsg() << "Failed to get coverage for seed " << SeedFile << ": " + << EC.message() << '\n'; + return 1; + } + + // Create a variable to represent the seed + const SeedID Var = Solver.newVar(); + SeedVars.push_back({Var, SeedFile}); + + // Record the set of seeds that cover a particular edge + for (const auto &[Edge, Freq] : Cov) { + if (EdgesOnly) { + // Ignore edge frequency + SeedCoverage[Edge].insert(Var); + } else { + // Executing edge `E` `N` times means that it was executed `N - 1` times + for (unsigned I = 0; I < Freq; ++I) + SeedCoverage[MAX_EDGE_FREQ * Edge + I].insert(Var); + } + } + + if ((++SeedCount % 10 == 0) && ShowProgBar) + ProgBar.update(SeedCount * 100 / NumSeeds, "Generating seed coverage"); + } + + EndTimer(ShowProgBar); + + // ------------------------------------------------------------------------ // + // Set the hard and soft constraints in the solver + // ------------------------------------------------------------------------ // + + if (!ShowProgBar) StatMsg() << "Generating constraints... "; + StartTimer(ShowProgBar); + + SeedCount = 0; + + // Ensure that at least one seed is selected that covers a particular edge + // (hard constraint) + std::vector Clauses; + for (const auto &[_, Seeds] : SeedCoverage) { + if (Seeds.empty()) continue; + + Clauses.clear(); + for (const auto &Seed : Seeds) + Clauses.push_back(Seed); + + Solver.addClause(Clauses); + + if ((++SeedCount % 10 == 0) && ShowProgBar) + ProgBar.update(SeedCount * 100 / SeedCoverage.size(), + "Generating clauses"); + } + + // Select the minimum number of seeds that cover a particular set of edges + // (soft constraint) + for (const auto &[Var, Seed] : SeedVars) + Solver.addWeightedClause({-Var}, Weights[sys::path::filename(Seed)]); + + EndTimer(ShowProgBar); + + // ------------------------------------------------------------------------ // + // Generate a solution + // ------------------------------------------------------------------------ // + + StatMsg() << "Solving... "; + StartTimer(/*ShowProgBar=*/false); + + const bool Solved = Solver.solve(); + + EndTimer(/*ShowProgBar=*/false); + + // ------------------------------------------------------------------------ // + // Save the solution + // + // This will copy the selected seeds to the given output directory. + // ------------------------------------------------------------------------ // + + SmallVector Solution; + SmallString<32> OutputSeed; + + if (Solved) { + for (const auto &[Var, Seed] : SeedVars) + if (Solver.getValue(Var) > 0) Solution.push_back(Seed); + } else { + ErrMsg() << "Failed to find an optimal solution for `" << CorpusDir + << "`\n"; + return 1; + } + + SuccMsg() << "Minimized corpus size: " << Solution.size() << " seeds\n"; + + if (!ShowProgBar) StatMsg() << "Copying to `" << OutputDir << "`... "; + StartTimer(ShowProgBar); + + SeedCount = 0; + + for (const auto &Seed : Solution) { + OutputSeed = OutputDir; + sys::path::append(OutputSeed, sys::path::filename(Seed)); + + if (EC = sys::fs::copy_file(Seed, OutputSeed)) { + WarnMsg() << "Failed to copy `" << Seed << "` to `" << OutputDir + << "`: " << EC.message() << '\n'; + } + + if ((++SeedCount % 10 == 0) && ShowProgBar) + ProgBar.update(SeedCount * 100 / Solution.size(), "Copying seeds"); + } + + EndTimer(ShowProgBar); + SuccMsg() << "Done!\n"; + + return 0; +} diff --git a/utils/optimin/src/ProgressBar.h b/utils/optimin/src/ProgressBar.h new file mode 100644 index 00000000..2f8d7403 --- /dev/null +++ b/utils/optimin/src/ProgressBar.h @@ -0,0 +1,58 @@ +/** + * Progress bar. + * + * Adapted from https://www.bfilipek.com/2020/02/inidicators.html + */ + +#pragma once + +#include +#include + +/// Display a progress bar in the terminal +class ProgressBar { + private: + const size_t BarWidth; + const std::string Fill; + const std::string Remainder; + + public: + ProgressBar() : ProgressBar(60, "#", " ") { + } + + ProgressBar(size_t Width, const llvm::StringRef F, const llvm::StringRef R) + : BarWidth(Width), Fill(F), Remainder(R) { + } + + void update(float Progress, const llvm::StringRef Status = "", + llvm::raw_ostream &OS = llvm::outs()) { + // No need to write once progress is 100% + if (Progress > 100.0f) return; + + // Move cursor to the first position on the same line and flush + OS << '\r'; + OS.flush(); + + // Start bar + OS << '['; + + const auto Completed = + static_cast(Progress * static_cast(BarWidth) / 100.0); + for (size_t I = 0; I < BarWidth; ++I) { + if (I <= Completed) { + OS << Fill; + } else { + OS << Remainder; + } + } + + // End bar + OS << ']'; + + // Write progress percentage + OS << ' ' << std::min(static_cast(Progress), size_t(100)) << '%'; + + // Write status text + OS << " " << Status; + } +}; -- cgit v1.2.3 From 60cbe5b4bec445438718d27dc0cfda6a4d5de81e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 21 Jul 2021 09:55:22 +0200 Subject: optimin nits --- utils/optimin/README.md | 49 ++++++++++++++++++--------- utils/optimin/build_optimin.sh | 7 ++-- utils/optimin/src/OptiMin.cpp | 75 +++++++++++++++++++++++++++++++++++++++++ utils/optimin/src/ProgressBar.h | 13 +++++++ 4 files changed, 126 insertions(+), 18 deletions(-) (limited to 'utils') diff --git a/utils/optimin/README.md b/utils/optimin/README.md index 5001b59d..ec9c4b0a 100644 --- a/utils/optimin/README.md +++ b/utils/optimin/README.md @@ -10,27 +10,46 @@ heuristic and/or greedy algorithms to identify these functionally distinct files. This means that minimized corpora are generally much smaller than those produced by other tools. -## Usage +## Building -To build the `optimin` executable (when cloned from github): +To build the `optimin` just execute the `build_optimin.sh` script. -```bash -# Ensure EvalMaxSAT is available -git submodule init -git submodule update +## Running -mkdir build -cd build +Running `optimin` is the same as running `afl-cmin`: -# You may have to specify -DLLVM_DIR=`llvm-config --cmakedir` if you have a -# non-standard LLVM install (e.g., install via apt) -cmake .. -make -j -make install +``` +Required parameters: + -i dir - input directory with starting corpus + -o dir - output directory for minimized files + +Execution control settings: + -f file - location read by the fuzzed program (stdin) + -m megs - memory limit for child process (none MB) + -t msec - run time limit for child process (none) + -O - use binary-only instrumentation (FRIDA mode) + -Q - use binary-only instrumentation (QEMU mode) + -U - use unicorn-based instrumentation (unicorn mode) + +Minimization settings: + -C - keep crashing inputs, reject everything else + -e - solve for edge coverage only, ignore hit counts + +For additional tips, please consult README.md + +Environment variables used: +AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp +AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash +AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up +AFL_KEEP_TRACES: leave the temporary /.traces directory +AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL) +AFL_NO_FORKSRV: run target via execve instead of using the forkserver +AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH +AFL_PRINT_FILENAMES: If set, the filename currently processed will be printed to stdout +AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary ``` -Otherwise, run the `build_optimin.sh` script. Running `optimin` is the same as -running `afl-cmin`. +Example: `optimin -i files -o seeds -- ./target @@` ### Weighted Minimizations diff --git a/utils/optimin/build_optimin.sh b/utils/optimin/build_optimin.sh index 7397aa45..9480f966 100755 --- a/utils/optimin/build_optimin.sh +++ b/utils/optimin/build_optimin.sh @@ -122,9 +122,10 @@ echo echo "[+] EvalMaxSAT successfully prepared!" echo "[+] Building OptiMin now." mkdir -p build -cd build -cmake .. -DLLVM_DIR=`$LLVM_CONFIG --cmakedir` -make -j$CORES +cd build || exit 1 +cmake .. -DLLVM_DIR=`$LLVM_CONFIG --cmakedir` || exit 1 +make -j$CORES || exit 1 cd .. echo +cp -fv build/src/optimin . || exit 1 echo "[+] OptiMin successfully built!" diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index e02fcbe5..4fbf3416 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -33,16 +33,20 @@ namespace { /// Ensure seed weights default to 1 class Weight { + public: Weight() : Weight(1){}; Weight(uint32_t V) : Value(V){}; operator unsigned() const { + return Value; + } private: const unsigned Value; + }; // -------------------------------------------------------------------------- // @@ -89,16 +93,27 @@ static std::string AFLShowmapPath; static bool TargetArgsHasAtAt = false; static const auto ErrMsg = [] { + return WithColor(errs(), HighlightColor::Error) << "[-] "; + }; + static const auto WarnMsg = [] { + return WithColor(errs(), HighlightColor::Warning) << "[-] "; + }; + static const auto SuccMsg = [] { + return WithColor(outs(), HighlightColor::String) << "[+] "; + }; + static const auto StatMsg = [] { + return WithColor(outs(), HighlightColor::Remark) << "[*] "; + }; static cl::opt CorpusDir("i", cl::desc("Input directory"), @@ -124,6 +139,7 @@ static cl::opt Timeout( static cl::opt CrashMode( "C", cl::desc("Keep crashing inputs, reject everything else")); static cl::opt QemuMode("Q", cl::desc("Use binary-only instrumentation")); + } // anonymous namespace // -------------------------------------------------------------------------- // @@ -131,24 +147,33 @@ static cl::opt QemuMode("Q", cl::desc("Use binary-only instrumentation")); // -------------------------------------------------------------------------- // static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { + SmallVector Lines; MB.getBuffer().trim().split(Lines, '\n'); unsigned Weight = 0; for (const auto &Line : Lines) { + const auto &[Seed, WeightStr] = Line.split(','); if (to_integer(WeightStr, Weight, 10)) { + Weights.try_emplace(Seed, Weight); + } else { + WarnMsg() << "Failed to read weight for `" << Seed << "`. Skipping...\n"; + } + } + } [[nodiscard]] static std::error_code getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { + Optional Redirects[] = {None, None, None}; std::error_code EC; @@ -159,6 +184,7 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ + AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", OutputPath}; if (TargetArgsHasAtAt) @@ -180,8 +206,10 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { // Parse afl-showmap output const auto CovOrErr = MemoryBuffer::getFile(OutputPath); if (EC = CovOrErr.getError()) { + sys::fs::remove(OutputPath); return EC; + } SmallVector Lines; @@ -191,21 +219,27 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { unsigned Freq = 0; for (const auto &Line : Lines) { + const auto &[EdgeStr, FreqStr] = Line.split(':'); to_integer(EdgeStr, Edge, 10); to_integer(FreqStr, Freq, 10); Cov.push_back({Edge, Freq}); + } return sys::fs::remove(OutputPath); + } static inline void StartTimer(bool ShowProgBar) { + StartTime = std::chrono::system_clock::now(); + } static inline void EndTimer(bool ShowProgBar) { + EndTime = std::chrono::system_clock::now(); Duration = std::chrono::duration_cast(EndTime - StartTime); @@ -214,6 +248,7 @@ static inline void EndTimer(bool ShowProgBar) { outs() << '\n'; else outs() << Duration.count() << "s\n"; + } // -------------------------------------------------------------------------- // @@ -221,6 +256,7 @@ static inline void EndTimer(bool ShowProgBar) { // -------------------------------------------------------------------------- // int main(int argc, char *argv[]) { + WeightsMap Weights; ProgressBar ProgBar; std::error_code EC; @@ -234,8 +270,10 @@ int main(int argc, char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); if (!sys::fs::is_directory(OutputDir)) { + ErrMsg() << "Invalid output directory `" << OutputDir << "`\n"; return 1; + } for (const auto &Arg : TargetArgs) @@ -247,9 +285,12 @@ int main(int argc, char *argv[]) { const auto AFLShowmapOrErr = sys::findProgramByName("afl-showmap"); if (AFLShowmapOrErr.getError()) { + ErrMsg() << "Failed to find afl-showmap. Check your PATH\n"; return 1; + } + AFLShowmapPath = *AFLShowmapOrErr; // ------------------------------------------------------------------------ // @@ -260,19 +301,23 @@ int main(int argc, char *argv[]) { // ------------------------------------------------------------------------ // if (WeightsFile != "") { + StatMsg() << "Reading weights from `" << WeightsFile << "`... "; StartTimer(/*ShowProgBar=*/false); const auto WeightsOrErr = MemoryBuffer::getFile(WeightsFile); if (EC = WeightsOrErr.getError()) { + ErrMsg() << "Failed to read weights from `" << WeightsFile << "`: " << EC.message() << '\n'; return 1; + } GetWeights(*WeightsOrErr.get(), Weights); EndTimer(/*ShowProgBar=*/false); + } // ------------------------------------------------------------------------ // @@ -289,20 +334,26 @@ int main(int argc, char *argv[]) { for (sys::fs::directory_iterator Dir(CorpusDir, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { + if (EC) { + ErrMsg() << "Failed to traverse corpus directory `" << CorpusDir << "`: " << EC.message() << '\n'; return 1; + } const auto &Path = Dir->path(); if (EC = sys::fs::status(Path, Status)) { + WarnMsg() << "Failed to access seed file `" << Path << "`: " << EC.message() << ". Skipping...\n"; continue; + } switch (Status.type()) { + case sys::fs::file_type::regular_file: case sys::fs::file_type::symlink_file: case sys::fs::file_type::type_unknown: @@ -310,7 +361,9 @@ int main(int argc, char *argv[]) { default: /* Ignore */ break; + } + } EndTimer(/*ShowProgBar=*/false); @@ -336,12 +389,15 @@ int main(int argc, char *argv[]) { AFLCoverageVector Cov; for (const auto &SeedFile : SeedFiles) { + // Execute seed Cov.clear(); if (EC = getAFLCoverage(SeedFile, Cov)) { + ErrMsg() << "Failed to get coverage for seed " << SeedFile << ": " << EC.message() << '\n'; return 1; + } // Create a variable to represent the seed @@ -350,18 +406,25 @@ int main(int argc, char *argv[]) { // Record the set of seeds that cover a particular edge for (const auto &[Edge, Freq] : Cov) { + if (EdgesOnly) { + // Ignore edge frequency SeedCoverage[Edge].insert(Var); + } else { + // Executing edge `E` `N` times means that it was executed `N - 1` times for (unsigned I = 0; I < Freq; ++I) SeedCoverage[MAX_EDGE_FREQ * Edge + I].insert(Var); + } + } if ((++SeedCount % 10 == 0) && ShowProgBar) ProgBar.update(SeedCount * 100 / NumSeeds, "Generating seed coverage"); + } EndTimer(ShowProgBar); @@ -379,6 +442,7 @@ int main(int argc, char *argv[]) { // (hard constraint) std::vector Clauses; for (const auto &[_, Seeds] : SeedCoverage) { + if (Seeds.empty()) continue; Clauses.clear(); @@ -390,6 +454,7 @@ int main(int argc, char *argv[]) { if ((++SeedCount % 10 == 0) && ShowProgBar) ProgBar.update(SeedCount * 100 / SeedCoverage.size(), "Generating clauses"); + } // Select the minimum number of seeds that cover a particular set of edges @@ -420,12 +485,16 @@ int main(int argc, char *argv[]) { SmallString<32> OutputSeed; if (Solved) { + for (const auto &[Var, Seed] : SeedVars) if (Solver.getValue(Var) > 0) Solution.push_back(Seed); + } else { + ErrMsg() << "Failed to find an optimal solution for `" << CorpusDir << "`\n"; return 1; + } SuccMsg() << "Minimized corpus size: " << Solution.size() << " seeds\n"; @@ -436,20 +505,26 @@ int main(int argc, char *argv[]) { SeedCount = 0; for (const auto &Seed : Solution) { + OutputSeed = OutputDir; sys::path::append(OutputSeed, sys::path::filename(Seed)); if (EC = sys::fs::copy_file(Seed, OutputSeed)) { + WarnMsg() << "Failed to copy `" << Seed << "` to `" << OutputDir << "`: " << EC.message() << '\n'; + } if ((++SeedCount % 10 == 0) && ShowProgBar) ProgBar.update(SeedCount * 100 / Solution.size(), "Copying seeds"); + } EndTimer(ShowProgBar); SuccMsg() << "Done!\n"; return 0; + } + diff --git a/utils/optimin/src/ProgressBar.h b/utils/optimin/src/ProgressBar.h index 2f8d7403..9b75594b 100644 --- a/utils/optimin/src/ProgressBar.h +++ b/utils/optimin/src/ProgressBar.h @@ -11,6 +11,7 @@ /// Display a progress bar in the terminal class ProgressBar { + private: const size_t BarWidth; const std::string Fill; @@ -18,14 +19,17 @@ class ProgressBar { public: ProgressBar() : ProgressBar(60, "#", " ") { + } ProgressBar(size_t Width, const llvm::StringRef F, const llvm::StringRef R) : BarWidth(Width), Fill(F), Remainder(R) { + } void update(float Progress, const llvm::StringRef Status = "", llvm::raw_ostream &OS = llvm::outs()) { + // No need to write once progress is 100% if (Progress > 100.0f) return; @@ -39,11 +43,17 @@ class ProgressBar { const auto Completed = static_cast(Progress * static_cast(BarWidth) / 100.0); for (size_t I = 0; I < BarWidth; ++I) { + if (I <= Completed) { + OS << Fill; + } else { + OS << Remainder; + } + } // End bar @@ -54,5 +64,8 @@ class ProgressBar { // Write status text OS << " " << Status; + } + }; + -- cgit v1.2.3 From a9328e40b3cf9cbda844da8bdce20093df7bbffa Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 21 Jul 2021 09:57:49 +0200 Subject: fix optimin readme --- utils/optimin/README.md | 55 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'utils') diff --git a/utils/optimin/README.md b/utils/optimin/README.md index ec9c4b0a..bea77225 100644 --- a/utils/optimin/README.md +++ b/utils/optimin/README.md @@ -19,34 +19,33 @@ To build the `optimin` just execute the `build_optimin.sh` script. Running `optimin` is the same as running `afl-cmin`: ``` -Required parameters: - -i dir - input directory with starting corpus - -o dir - output directory for minimized files - -Execution control settings: - -f file - location read by the fuzzed program (stdin) - -m megs - memory limit for child process (none MB) - -t msec - run time limit for child process (none) - -O - use binary-only instrumentation (FRIDA mode) - -Q - use binary-only instrumentation (QEMU mode) - -U - use unicorn-based instrumentation (unicorn mode) - -Minimization settings: - -C - keep crashing inputs, reject everything else - -e - solve for edge coverage only, ignore hit counts - -For additional tips, please consult README.md - -Environment variables used: -AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp -AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash -AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up -AFL_KEEP_TRACES: leave the temporary /.traces directory -AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL) -AFL_NO_FORKSRV: run target via execve instead of using the forkserver -AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH -AFL_PRINT_FILENAMES: If set, the filename currently processed will be printed to stdout -AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary +./optimin -h +OVERVIEW: Optimal corpus minimizer +USAGE: optimin [options] [target args...] + +OPTIONS: + +Color Options: + + --color - Use colors in output (default=autodetect) + +General options: + + -C - Keep crashing inputs, reject everything else + -Q - Use binary-only instrumentation + -f - Include edge hit counts + -i dir - Input directory + -m megs - Memory limit for child process (default=none) + -o dir - Output directory + -p - Display progress bar + -t msec - Run time limit for child process (default=none) + -w csv - Weights file + +Generic Options: + + --help - Display available options (--help-hidden for more) + --help-list - Display list of available options (--help-list-hidden for more) + --version - Display the version of this program ``` Example: `optimin -i files -o seeds -- ./target @@` -- cgit v1.2.3 From 183d9a3f07acf0ab9bb28359c2c0852eab8e7c10 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 22 Jul 2021 15:16:04 +0200 Subject: MacOS nits --- utils/optimin/src/OptiMin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 4fbf3416..b82acbb6 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -134,8 +134,8 @@ static cl::opt MemLimit( "m", cl::desc("Memory limit for child process (default=none)"), cl::value_desc("megs"), cl::init("none")); static cl::opt Timeout( - "t", cl::desc("Run time limit for child process (default=none)"), - cl::value_desc("msec"), cl::init("none")); + "t", cl::desc("Run time limit for child process (default=5000)"), + cl::value_desc("msec"), cl::init("4000")); static cl::opt CrashMode( "C", cl::desc("Keep crashing inputs, reject everything else")); static cl::opt QemuMode("Q", cl::desc("Use binary-only instrumentation")); -- cgit v1.2.3 From 0f299a3bef12b2a8f27a5ba629a2ecb1201fcd60 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 23 Jul 2021 13:29:53 +0200 Subject: removed utils/afl_frida --- utils/README.md | 15 ++ utils/afl_frida/GNUmakefile | 23 -- utils/afl_frida/Makefile | 2 - utils/afl_frida/README.md | 34 --- utils/afl_frida/afl-frida.c | 397 ---------------------------- utils/afl_frida/afl-frida.h | 53 ---- utils/afl_frida/android/README.md | 1 - utils/afl_frida/android/frida-gum-example.c | 130 --------- utils/afl_frida/libtestinstr.c | 35 --- utils/qbdi_mode/README.md | 2 +- 10 files changed, 16 insertions(+), 676 deletions(-) delete mode 100644 utils/afl_frida/GNUmakefile delete mode 100644 utils/afl_frida/Makefile delete mode 100644 utils/afl_frida/README.md delete mode 100644 utils/afl_frida/afl-frida.c delete mode 100644 utils/afl_frida/afl-frida.h delete mode 100644 utils/afl_frida/android/README.md delete mode 100644 utils/afl_frida/android/frida-gum-example.c delete mode 100644 utils/afl_frida/libtestinstr.c (limited to 'utils') diff --git a/utils/README.md b/utils/README.md index 92619fd0..eb2e36b7 100644 --- a/utils/README.md +++ b/utils/README.md @@ -2,6 +2,9 @@ Here's a quick overview of the stuff you can find in this directory: + - aflpp_driver - easily instrument LLVMFuzzerTestOneInput() + harnesses. + - afl_network_proxy - fuzz a target over the network: afl-fuzz on a host, target on an embedded system. @@ -12,12 +15,16 @@ Here's a quick overview of the stuff you can find in this directory: - afl_untracer - fuzz binary-only libraries much faster but with less coverage than qemu_mode + - analysis_scripts - random -o out analysis scripts + - argv_fuzzing - a simple wrapper to allow cmdline to be fuzzed (e.g., to test setuid programs). - asan_cgroups - a contributed script to simplify fuzzing ASAN binaries with robust memory limits on Linux. + - autodict_ql - generate dictionary files from source code. + - bash_shellshock - a simple hack used to find a bunch of post-Shellshock bugs in bash. @@ -35,9 +42,15 @@ Here's a quick overview of the stuff you can find in this directory: C and Python. Note: They were moved to ../custom_mutators/examples/ + - defork - intercept fork() in targets + - distributed_fuzzing - a sample script for synchronizing fuzzer instances across multiple machines (see parallel_fuzzing.md). + - libdislocator - like ASAN but lightweight. + + - libtokencap - collect string tokens for a dictionary. + - libpng_no_checksum - a sample patch for removing CRC checks in libpng. - optimin - An optimal corpus minimizer. @@ -45,6 +58,8 @@ Here's a quick overview of the stuff you can find in this directory: - persistent_mode - an example of how to use the LLVM persistent process mode to speed up certain fuzzing jobs. + - qemu_persistent_hook - persistent mode support module for qemu. + - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin for fuzzing access with afl++ diff --git a/utils/afl_frida/GNUmakefile b/utils/afl_frida/GNUmakefile deleted file mode 100644 index 8b56415b..00000000 --- a/utils/afl_frida/GNUmakefile +++ /dev/null @@ -1,23 +0,0 @@ -ifdef DEBUG - OPT=-O0 -D_DEBUG=\"1\" -else - OPT=-O3 -funroll-loops -endif - -all: afl-frida libtestinstr.so - -libfrida-gum.a: - @echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest - @exit 1 - -afl-frida: afl-frida.c libfrida-gum.a - $(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-compiler-rt.o libfrida-gum.a -ldl -lresolv -pthread - -libtestinstr.so: libtestinstr.c - $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c - -clean: - rm -f afl-frida *~ core *.o libtestinstr.so - -deepclean: clean - rm -f libfrida-gum.a frida-gum* diff --git a/utils/afl_frida/Makefile b/utils/afl_frida/Makefile deleted file mode 100644 index 0b306dde..00000000 --- a/utils/afl_frida/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - @echo please use GNU make, thanks! diff --git a/utils/afl_frida/README.md b/utils/afl_frida/README.md deleted file mode 100644 index 68b62009..00000000 --- a/utils/afl_frida/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# afl-frida - faster fuzzing of binary-only libraries - -## Introduction - -afl-frida is an example skeleton file which can easily be used to fuzz -a closed source library. - -It requires less memory and is x5-10 faster than qemu_mode but does not -provide interesting features like compcov or cmplog. - -## How-to - -### Modify afl-frida.c - -Read and modify afl-frida.c then `make`. -To adapt afl-frida.c to your needs, read the header of the file and then -search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. - -### Fuzzing - -Example (after modifying afl-frida.c to your needs and compile it): -``` -LD_LIBRARY_PATH=/path/to/the/target/library/ afl-fuzz -i in -o out -- ./afl-frida -``` -(or even remote via afl-network-proxy). - -# Speed and stability - -The speed is very good, about x12 of fork() qemu_mode. -However the stability is low. Reason is currently unknown. - -# Background - -This code is copied for a larger part from https://github.com/meme/hotwax diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c deleted file mode 100644 index e49d6f42..00000000 --- a/utils/afl_frida/afl-frida.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - american fuzzy lop++ - afl-frida skeleton example - ------------------------------------------------- - - Copyright 2020 AFLplusplus Project. All rights reserved. - - Written mostly by meme -> https://github.com/meme/hotwax - - Modifications by Marc Heuse - - 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 - - HOW-TO - ====== - - You only need to change the following: - - 1. set the defines and function call parameters. - 2. dl load the library you want to fuzz, lookup the functions you need - and setup the calls to these. - 3. in the while loop you call the functions in the necessary order - - incl the cleanup. the cleanup is important! - - Just look these steps up in the code, look for "// STEP x:" - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ - #include - #include -#else - #include - #include -#endif - -int debug = 0; - -// STEP 1: - -// The presets are for the example libtestinstr.so: - -/* What is the name of the library to fuzz */ -#define TARGET_LIBRARY "libtestinstr.so" - -/* What is the name of the function to fuzz */ -#define TARGET_FUNCTION "testinstr" - -/* here you need to specify the parameter for the target function */ -static void *(*o_function)(uint8_t *, int); - -// END STEP 1 - -#include "frida-gum.h" - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); -void afl_setup(void); -void afl_start_forkserver(void); -int __afl_persistent_loop(unsigned int max_cnt); - -#include "../../config.h" - -// Shared memory fuzzing. -int __afl_sharedmem_fuzzing = 1; -extern unsigned int * __afl_fuzz_len; -extern unsigned char *__afl_fuzz_ptr; - -// Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##\0"; -int __afl_persistent_loop(unsigned int); - -// Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##\0"; -void __afl_manual_init(); - -// Because we do our own logging. -extern uint8_t * __afl_area_ptr; -static __thread guint64 previous_pc; - -// Frida stuff below. -typedef struct { - - GumAddress base_address; - guint64 code_start, code_end; - GumAddress current_log_impl; - uint64_t afl_prev_loc; - -} range_t; - -inline static void afl_maybe_log(guint64 current_pc) { - - // fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc); - - 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; - -} - -#ifdef __x86_64__ - -static const guint8 afl_maybe_log_code[] = { - - 0x9c, // pushfq - 0x50, // push rax - 0x51, // push rcx - 0x52, // push rdx - 0x56, // push rsi - - 0x89, 0xf8, // mov eax, edi - 0xc1, 0xe0, 0x08, // shl eax, 8 - 0xc1, 0xef, 0x04, // shr edi, 4 - 0x31, 0xc7, // xor edi, eax - 0x0f, 0xb7, 0xc7, // movzx eax, di - 0x48, 0x8d, 0x0d, 0x30, 0x00, 0x00, 0x00, // lea rcx, sym._afl_area_ptr_ptr - 0x48, 0x8b, 0x09, // mov rcx, qword [rcx] - 0x48, 0x8b, 0x09, // mov rcx, qword [rcx] - 0x48, 0x8d, 0x15, 0x1b, 0x00, 0x00, 0x00, // lea rdx, sym._afl_prev_loc_ptr - 0x48, 0x8b, 0x32, // mov rsi, qword [rdx] - 0x48, 0x8b, 0x36, // mov rsi, qword [rsi] - 0x48, 0x31, 0xc6, // xor rsi, rax - 0xfe, 0x04, 0x31, // inc byte [rcx + rsi] - - 0x48, 0xd1, 0xe8, // shr rax, 1 - 0x48, 0x8b, 0x0a, // mov rcx, qword [rdx] - 0x48, 0x89, 0x01, // mov qword [rcx], rax - - 0x5e, // pop rsi - 0x5a, // pop rdx - 0x59, // pop rcx - 0x58, // pop rax - 0x9d, // popfq - - 0xc3, // ret - // Read-only data goes here: - // uint64_t* afl_prev_loc_ptr - // uint8_t** afl_area_ptr_ptr - // unsigned int afl_instr_rms - -}; - -#else - -static void on_basic_block(GumCpuContext *context, gpointer user_data) { - - afl_maybe_log((guint64)user_data); - -} - -#endif - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data) { - - range_t *range = (range_t *)user_data; - - const cs_insn *instr; - gboolean begin = TRUE; - while (gum_stalker_iterator_next(iterator, &instr)) { - - if (begin) { - - if (instr->address >= range->code_start && - instr->address <= range->code_end) { - -#ifdef __x86_64__ - GumX86Writer *cw = output->writer.x86; - if (range->current_log_impl == 0 || - !gum_x86_writer_can_branch_directly_between( - cw->pc, range->current_log_impl) || - !gum_x86_writer_can_branch_directly_between( - cw->pc + 128, range->current_log_impl)) { - - gconstpointer after_log_impl = cw->code + 1; - - gum_x86_writer_put_jmp_near_label(cw, after_log_impl); - - range->current_log_impl = cw->pc; - gum_x86_writer_put_bytes(cw, afl_maybe_log_code, - sizeof(afl_maybe_log_code)); - - uint64_t *afl_prev_loc_ptr = &range->afl_prev_loc; - uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, - sizeof(afl_prev_loc_ptr)); - gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, - sizeof(afl_area_ptr_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, - GUM_ADDRESS(instr->address)); - gum_x86_writer_put_call_address(cw, range->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); -#else - gum_stalker_iterator_put_callout(iterator, on_basic_block, - (gpointer)instr->address, NULL); -#endif - begin = FALSE; - - } - - } - - gum_stalker_iterator_keep(iterator); - - } - -} - -/* Because this CAN be called more than once, it will return the LAST range */ -static int enumerate_ranges(const GumRangeDetails *details, - gpointer user_data) { - - GumMemoryRange *code_range = (GumMemoryRange *)user_data; - memcpy(code_range, details->range, sizeof(*code_range)); - return 0; - -} - -int main(int argc, char **argv) { - -#ifndef __APPLE__ - (void)personality(ADDR_NO_RANDOMIZE); // disable ASLR -#endif - - // STEP 2: load the library you want to fuzz and lookup the functions, - // inclusive of the cleanup functions. - // If there is just one function, then there is nothing to change - // or add here. - - void *dl = NULL; - if (argc > 2) { - - dl = dlopen(argv[1], RTLD_LAZY); - - } else { - - dl = dlopen(TARGET_LIBRARY, RTLD_LAZY); - - } - - if (!dl) { - - if (argc > 2) - fprintf(stderr, "Could not load %s\n", argv[1]); - else - fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY); - exit(-1); - - } - - if (argc > 2) - o_function = dlsym(dl, argv[2]); - else - o_function = dlsym(dl, TARGET_FUNCTION); - if (!o_function) { - - if (argc > 2) - fprintf(stderr, "Could not find function %s\n", argv[2]); - else - fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION); - exit(-1); - - } - - // END STEP 2 - - if (!getenv("AFL_FRIDA_TEST_INPUT")) { - - gum_init_embedded(); - if (!gum_stalker_is_supported()) { - - gum_deinit_embedded(); - return 1; - - } - - GumStalker *stalker = gum_stalker_new(); - - GumAddress base_address; - if (argc > 2) - base_address = gum_module_find_base_address(argv[1]); - else - base_address = gum_module_find_base_address(TARGET_LIBRARY); - GumMemoryRange code_range; - if (argc > 2) - gum_module_enumerate_ranges(argv[1], GUM_PAGE_RX, enumerate_ranges, - &code_range); - else - gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges, - &code_range); - - guint64 code_start = code_range.base_address; - guint64 code_end = code_range.base_address + code_range.size; - range_t instr_range = {0, code_start, code_end, 0, 0}; - - printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n", - base_address, code_start, code_end); - if (!code_start || !code_end) { - - if (argc > 2) - fprintf(stderr, "Error: no valid memory address found for %s\n", - argv[1]); - else - fprintf(stderr, "Error: no valid memory address found for %s\n", - TARGET_LIBRARY); - exit(-1); - - } - - GumStalkerTransformer *transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, - &instr_range, NULL); - - // to ensure that the signatures are not optimized out - memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); - memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR, - sizeof(AFL_DEFER_FORKSVR)); - __afl_manual_init(); - - // - // any expensive target library initialization that has to be done just once - // - put that here - // - - gum_stalker_follow_me(stalker, transformer, NULL); - - while (__afl_persistent_loop(UINT32_MAX) != 0) { - - previous_pc = 0; // Required! - -#ifdef _DEBUG - fprintf(stderr, "CLIENT crc: %016llx len: %u\n", - hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len); - fprintf(stderr, "RECV:"); - for (int i = 0; i < *__afl_fuzz_len; i++) - fprintf(stderr, "%02x", __afl_fuzz_ptr[i]); - fprintf(stderr, "\n"); -#endif - - // STEP 3: ensure the minimum length is present and setup the target - // function to fuzz. - - if (*__afl_fuzz_len > 0) { - - __afl_fuzz_ptr[*__afl_fuzz_len] = 0; // if you need to null terminate - (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len); - - } - - // END STEP 3 - - } - - gum_stalker_unfollow_me(stalker); - - while (gum_stalker_garbage_collect(stalker)) - g_usleep(10000); - - g_object_unref(stalker); - g_object_unref(transformer); - gum_deinit_embedded(); - - } else { - - char buf[8 * 1024] = {0}; - int count = read(0, buf, sizeof(buf)); - buf[8 * 1024 - 1] = '\0'; - (*o_function)(buf, count); - - } - - return 0; - -} - diff --git a/utils/afl_frida/afl-frida.h b/utils/afl_frida/afl-frida.h deleted file mode 100644 index efa3440f..00000000 --- a/utils/afl_frida/afl-frida.h +++ /dev/null @@ -1,53 +0,0 @@ -extern int is_persistent; - -G_BEGIN_DECLS - -#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type()) - -G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM, - FAKE_EVENT_SINK, GObject) - -struct _GumFakeEventSink { - - GObject parent; - GumEventType mask; - -}; - -GumEventSink *gum_fake_event_sink_new(void); -void gum_fake_event_sink_reset(GumFakeEventSink *self); - -G_END_DECLS - -typedef struct { - - GumAddress base_address; - guint64 code_start, code_end; - -} range_t; - -void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output, - gpointer user_data); -#pragma once - -void afl_setup(void); -void afl_start_forkserver(void); -int __afl_persistent_loop(unsigned int max_cnt); - -inline static inline void afl_maybe_log(guint64 current_pc) { - - extern unsigned int afl_instr_rms; - extern uint8_t * afl_area_ptr; - - static __thread guint64 previous_pc; - - current_pc = (current_pc >> 4) ^ (current_pc << 8); - current_pc &= MAP_SIZE - 1; - - if (current_pc >= afl_instr_rms) return; - - afl_area_ptr[current_pc ^ previous_pc]++; - previous_pc = current_pc >> 1; - -} - diff --git a/utils/afl_frida/android/README.md b/utils/afl_frida/android/README.md deleted file mode 100644 index 044b48a1..00000000 --- a/utils/afl_frida/android/README.md +++ /dev/null @@ -1 +0,0 @@ -For android, frida-gum package (ex. https://github.com/frida/frida/releases/download/14.2.6/frida-gum-devkit-14.2.6-android-arm64.tar.xz) is needed to be extracted in the directory. diff --git a/utils/afl_frida/android/frida-gum-example.c b/utils/afl_frida/android/frida-gum-example.c deleted file mode 100644 index 14d98248..00000000 --- a/utils/afl_frida/android/frida-gum-example.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Compile with: - * - * clang -fPIC -DANDROID -ffunction-sections -fdata-sections -Os -pipe -g3 frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread -Wl,--gc-sections,-z,noexecstack,-z,relro,-z,now -fuse-ld=gold -fuse-ld=gold -Wl,--icf=all - * - * Visit https://frida.re to learn more about Frida. - */ - -#include "frida-gum.h" - -#include -#include - -typedef struct _ExampleListener ExampleListener; -typedef enum _ExampleHookId ExampleHookId; - -struct _ExampleListener -{ - GObject parent; - - guint num_calls; -}; - -enum _ExampleHookId -{ - EXAMPLE_HOOK_OPEN, - EXAMPLE_HOOK_CLOSE -}; - -static void example_listener_iface_init (gpointer g_iface, gpointer iface_data); - -#define EXAMPLE_TYPE_LISTENER (example_listener_get_type ()) -G_DECLARE_FINAL_TYPE (ExampleListener, example_listener, EXAMPLE, LISTENER, GObject) -G_DEFINE_TYPE_EXTENDED (ExampleListener, - example_listener, - G_TYPE_OBJECT, - 0, - G_IMPLEMENT_INTERFACE (GUM_TYPE_INVOCATION_LISTENER, - example_listener_iface_init)) - -int -main (int argc, - char * argv[]) -{ - GumInterceptor * interceptor; - GumInvocationListener * listener; - - gum_init_embedded (); - - interceptor = gum_interceptor_obtain (); - listener = g_object_new (EXAMPLE_TYPE_LISTENER, NULL); - - gum_interceptor_begin_transaction (interceptor); - gum_interceptor_attach (interceptor, - GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "open")), - listener, - GSIZE_TO_POINTER (EXAMPLE_HOOK_OPEN)); - gum_interceptor_attach (interceptor, - GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "close")), - listener, - GSIZE_TO_POINTER (EXAMPLE_HOOK_CLOSE)); - gum_interceptor_end_transaction (interceptor); - - close (open ("/etc/hosts", O_RDONLY)); - close (open ("/etc/fstab", O_RDONLY)); - - g_print ("[*] listener got %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); - - gum_interceptor_detach (interceptor, listener); - - close (open ("/etc/hosts", O_RDONLY)); - close (open ("/etc/fstab", O_RDONLY)); - - g_print ("[*] listener still has %u calls\n", EXAMPLE_LISTENER (listener)->num_calls); - - g_object_unref (listener); - g_object_unref (interceptor); - - gum_deinit_embedded (); - - return 0; -} - -static void -example_listener_on_enter (GumInvocationListener * listener, - GumInvocationContext * ic) -{ - ExampleListener * self = EXAMPLE_LISTENER (listener); - ExampleHookId hook_id = GUM_IC_GET_FUNC_DATA (ic, ExampleHookId); - - switch (hook_id) - { - case EXAMPLE_HOOK_OPEN: - g_print ("[*] open(\"%s\")\n", (const gchar *) gum_invocation_context_get_nth_argument (ic, 0)); - break; - case EXAMPLE_HOOK_CLOSE: - g_print ("[*] close(%d)\n", GPOINTER_TO_INT (gum_invocation_context_get_nth_argument (ic, 0))); - break; - } - - self->num_calls++; -} - -static void -example_listener_on_leave (GumInvocationListener * listener, - GumInvocationContext * ic) -{ -} - -static void -example_listener_class_init (ExampleListenerClass * klass) -{ - (void) EXAMPLE_IS_LISTENER; - (void) glib_autoptr_cleanup_ExampleListener; -} - -static void -example_listener_iface_init (gpointer g_iface, - gpointer iface_data) -{ - GumInvocationListenerInterface * iface = g_iface; - - iface->on_enter = example_listener_on_enter; - iface->on_leave = example_listener_on_leave; -} - -static void -example_listener_init (ExampleListener * self) -{ -} diff --git a/utils/afl_frida/libtestinstr.c b/utils/afl_frida/libtestinstr.c deleted file mode 100644 index 96b1cf21..00000000 --- a/utils/afl_frida/libtestinstr.c +++ /dev/null @@ -1,35 +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 -#include -#include - -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"); - -} - diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index cf5d3359..334199f2 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -2,7 +2,7 @@ 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. +Try frida_mode/ or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. ## 1) Introduction -- cgit v1.2.3 From e64aa5757668be774212bc2016bf0bf312f7304f Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 23 Jul 2021 21:33:32 +0200 Subject: aligned wording --- utils/afl_network_proxy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/afl_network_proxy/README.md b/utils/afl_network_proxy/README.md index a5ac3578..05659c45 100644 --- a/utils/afl_network_proxy/README.md +++ b/utils/afl_network_proxy/README.md @@ -32,7 +32,7 @@ e.g.: afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ ``` -### on the (afl-fuzz) master +### on the (afl-fuzz) main node Just run afl-fuzz with your normal options, however the target should be `afl-network-client` with the IP and PORT of the `afl-network-server` and -- cgit v1.2.3 From 99d24d13f1ad972ab0645cf81155b47a7e693a42 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Thu, 22 Jul 2021 11:19:57 +0000 Subject: optimin: add missing cmin options and auto create output dir * Includes frida, unicorn modes * Automatically create the output directory if it does not already exist --- utils/optimin/README.md | 4 +++- utils/optimin/src/OptiMin.cpp | 32 +++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'utils') diff --git a/utils/optimin/README.md b/utils/optimin/README.md index bea77225..3036b449 100644 --- a/utils/optimin/README.md +++ b/utils/optimin/README.md @@ -32,7 +32,9 @@ Color Options: General options: -C - Keep crashing inputs, reject everything else - -Q - Use binary-only instrumentation + -O - Use binary-only instrumentation (FRIDA mode) + -Q - Use binary-only instrumentation (QEMU mode) + -U - Use unicorn-based instrumentation (unicorn mode) -f - Include edge hit counts -i dir - Input directory -m megs - Memory limit for child process (default=none) diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index b82acbb6..55e391df 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -116,29 +116,38 @@ static const auto StatMsg = [] { }; -static cl::opt CorpusDir("i", cl::desc("Input directory"), +static cl::opt CorpusDir("i", cl::desc("Input directory"), cl::value_desc("dir"), cl::Required); -static cl::opt OutputDir("o", cl::desc("Output directory"), +static cl::opt OutputDir("o", cl::desc("Output directory"), cl::value_desc("dir"), cl::Required); -static cl::opt EdgesOnly("f", cl::desc("Include edge hit counts"), + +static cl::opt ShowProgBar("p", cl::desc("Display progress bar")); +static cl::opt EdgesOnly("f", cl::desc("Include edge hit counts"), cl::init(true)); -static cl::opt ShowProgBar("p", cl::desc("Display progress bar")); -static cl::opt WeightsFile("w", cl::desc("Weights file"), +static cl::opt WeightsFile("w", cl::desc("Weights file"), cl::value_desc("csv")); + static cl::opt TargetProg(cl::Positional, cl::desc(""), cl::Required); static cl::list TargetArgs(cl::ConsumeAfter, cl::desc("[target args...]")); -static cl::opt MemLimit( + +static cl::opt MemLimit( "m", cl::desc("Memory limit for child process (default=none)"), cl::value_desc("megs"), cl::init("none")); static cl::opt Timeout( "t", cl::desc("Run time limit for child process (default=5000)"), cl::value_desc("msec"), cl::init("4000")); + static cl::opt CrashMode( "C", cl::desc("Keep crashing inputs, reject everything else")); -static cl::opt QemuMode("Q", cl::desc("Use binary-only instrumentation")); +static cl::opt FridaMode( + "O", cl::desc("Use binary-only instrumentation (FRIDA mode)")); +static cl::opt QemuMode( + "Q", cl::desc("Use binary-only instrumentation (QEMU mode)")); +static cl::opt UnicornMode( + "U", cl::desc("Use unicorn-based instrumentation (unicorn mode)")); } // anonymous namespace @@ -184,7 +193,6 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ - AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", OutputPath}; if (TargetArgsHasAtAt) @@ -192,8 +200,9 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { else Redirects[/* stdin */ 0] = Seed; + if (FridaMode) AFLShowmapArgs.push_back("-O"); if (QemuMode) AFLShowmapArgs.push_back("-Q"); - if (CrashMode) AFLShowmapArgs.push_back("-C"); + if (UnicornMode) AFLShowmapArgs.push_back("-U"); AFLShowmapArgs.append({"--", TargetProg}); AFLShowmapArgs.append(TargetArgs.begin(), TargetArgs.end()); @@ -269,9 +278,10 @@ int main(int argc, char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); - if (!sys::fs::is_directory(OutputDir)) { + if (EC = sys::fs::create_directory(OutputDir)) { - ErrMsg() << "Invalid output directory `" << OutputDir << "`\n"; + ErrMsg() << "Invalid output directory `" << OutputDir + << "`: " << EC.message() << '\n'; return 1; } -- cgit v1.2.3 From 7123dd9d299206e7e21cbc8152abb0666acb170f Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 23 Jul 2021 08:23:29 +0000 Subject: optimin: improve afl-showmap error messages --- utils/optimin/src/OptiMin.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 55e391df..dca433cc 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -180,16 +181,18 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { } -[[nodiscard]] static std::error_code getAFLCoverage(const StringRef Seed, - AFLCoverageVector &Cov) { +static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { Optional Redirects[] = {None, None, None}; - std::error_code EC; // Create temporary output file - SmallString<64> OutputPath; - if (EC = sys::fs::createTemporaryFile("showmap", "txt", OutputPath)) - return EC; + SmallString<32> OutputPath; + if (const auto EC = sys::fs::createTemporaryFile("showmap", "txt", OutputPath)) { + + return createStringError( + EC, "Failed to create temporary file for afl-showmap output"); + + } // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ @@ -210,14 +213,16 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { // Run afl-showmap const int RC = sys::ExecuteAndWait(AFLShowmapPath, AFLShowmapArgs, /*env=*/None, Redirects); - if (RC) return std::make_error_code(std::errc::executable_format_error); + if (RC) + return createStringError(inconvertibleErrorCode(), "afl-showmap failed"); // Parse afl-showmap output const auto CovOrErr = MemoryBuffer::getFile(OutputPath); - if (EC = CovOrErr.getError()) { + if (const auto EC = CovOrErr.getError()) { sys::fs::remove(OutputPath); - return EC; + return createStringError(EC, "Failed to read afl-showmap output file `%s`", + OutputPath.c_str()); } @@ -237,7 +242,8 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { } - return sys::fs::remove(OutputPath); + sys::fs::remove(OutputPath); + return Error::success(); } @@ -278,7 +284,7 @@ int main(int argc, char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); - if (EC = sys::fs::create_directory(OutputDir)) { + if ((EC = sys::fs::create_directory(OutputDir))) { ErrMsg() << "Invalid output directory `" << OutputDir << "`: " << EC.message() << '\n'; @@ -316,7 +322,7 @@ int main(int argc, char *argv[]) { StartTimer(/*ShowProgBar=*/false); const auto WeightsOrErr = MemoryBuffer::getFile(WeightsFile); - if (EC = WeightsOrErr.getError()) { + if ((EC = WeightsOrErr.getError())) { ErrMsg() << "Failed to read weights from `" << WeightsFile << "`: " << EC.message() << '\n'; @@ -354,7 +360,7 @@ int main(int argc, char *argv[]) { } const auto &Path = Dir->path(); - if (EC = sys::fs::status(Path, Status)) { + if ((EC = sys::fs::status(Path, Status))) { WarnMsg() << "Failed to access seed file `" << Path << "`: " << EC.message() << ". Skipping...\n"; @@ -402,10 +408,10 @@ int main(int argc, char *argv[]) { // Execute seed Cov.clear(); - if (EC = getAFLCoverage(SeedFile, Cov)) { + if (auto Err = getAFLCoverage(SeedFile, Cov)) { - ErrMsg() << "Failed to get coverage for seed " << SeedFile << ": " - << EC.message() << '\n'; + ErrMsg() << "Failed to get coverage for seed `" << SeedFile << "`: " + << Err << '\n'; return 1; } @@ -519,7 +525,7 @@ int main(int argc, char *argv[]) { OutputSeed = OutputDir; sys::path::append(OutputSeed, sys::path::filename(Seed)); - if (EC = sys::fs::copy_file(Seed, OutputSeed)) { + if ((EC = sys::fs::copy_file(Seed, OutputSeed))) { WarnMsg() << "Failed to copy `" << Seed << "` to `" << OutputDir << "`: " << EC.message() << '\n'; -- cgit v1.2.3 From 64daf1058407985697874df9a4860bddd4fa3f1b Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 23 Jul 2021 08:25:49 +0000 Subject: optimin: recursively iterate over input directory --- utils/optimin/src/OptiMin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index dca433cc..b6997939 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -348,7 +348,7 @@ int main(int argc, char *argv[]) { std::vector SeedFiles; sys::fs::file_status Status; - for (sys::fs::directory_iterator Dir(CorpusDir, EC), DirEnd; + for (sys::fs::recursive_directory_iterator Dir(CorpusDir, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { if (EC) { -- cgit v1.2.3 From aebb14ceeb5af441c49919802386bcfc18e3574d Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Sat, 24 Jul 2021 01:14:53 +0000 Subject: optimin: add support for afl-cmin env vars --- utils/optimin/src/OptiMin.cpp | 64 ++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 22 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index b6997939..8d839911 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -92,6 +93,7 @@ static std::chrono::seconds Duration; static std::string AFLShowmapPath; static bool TargetArgsHasAtAt = false; +static bool KeepTraces = false; static const auto ErrMsg = [] { @@ -185,18 +187,12 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { Optional Redirects[] = {None, None, None}; - // Create temporary output file - SmallString<32> OutputPath; - if (const auto EC = sys::fs::createTemporaryFile("showmap", "txt", OutputPath)) { - - return createStringError( - EC, "Failed to create temporary file for afl-showmap output"); - - } + SmallString<32> TracePath{OutputDir}; + sys::path::append(TracePath, ".traces", sys::path::filename(Seed)); // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ - AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", OutputPath}; + AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", TracePath}; if (TargetArgsHasAtAt) AFLShowmapArgs.append({"-A", Seed}); @@ -217,12 +213,12 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { return createStringError(inconvertibleErrorCode(), "afl-showmap failed"); // Parse afl-showmap output - const auto CovOrErr = MemoryBuffer::getFile(OutputPath); + const auto CovOrErr = MemoryBuffer::getFile(TracePath); if (const auto EC = CovOrErr.getError()) { - sys::fs::remove(OutputPath); + sys::fs::remove(TracePath); return createStringError(EC, "Failed to read afl-showmap output file `%s`", - OutputPath.c_str()); + TracePath.c_str()); } @@ -242,7 +238,7 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { } - sys::fs::remove(OutputPath); + if (!KeepTraces) sys::fs::remove(TracePath); return Error::success(); } @@ -277,20 +273,15 @@ int main(int argc, char *argv[]) { std::error_code EC; // ------------------------------------------------------------------------ // - // Parse command-line options + // Parse command-line options and environment variables // // Also check the target arguments, as this determines how we run afl-showmap. // ------------------------------------------------------------------------ // cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); - if ((EC = sys::fs::create_directory(OutputDir))) { - - ErrMsg() << "Invalid output directory `" << OutputDir - << "`: " << EC.message() << '\n'; - return 1; - - } + KeepTraces = !!std::getenv("AFL_KEEP_TRACES"); + const auto AFLPath = std::getenv("AFL_PATH"); for (const auto &Arg : TargetArgs) if (Arg == "@@") TargetArgsHasAtAt = true; @@ -299,7 +290,13 @@ int main(int argc, char *argv[]) { // Find afl-showmap // ------------------------------------------------------------------------ // - const auto AFLShowmapOrErr = sys::findProgramByName("afl-showmap"); + SmallVector EnvPaths; + + if (const char *PathEnv = std::getenv("PATH")) + SplitString(PathEnv, EnvPaths, ":"); + if (AFLPath) EnvPaths.push_back(AFLPath); + + const auto AFLShowmapOrErr = sys::findProgramByName("afl-showmap", EnvPaths); if (AFLShowmapOrErr.getError()) { ErrMsg() << "Failed to find afl-showmap. Check your PATH\n"; @@ -336,6 +333,29 @@ int main(int argc, char *argv[]) { } + // ------------------------------------------------------------------------ // + // Setup output directory + // ------------------------------------------------------------------------ // + + SmallString<32> TraceDir{OutputDir}; + sys::path::append(TraceDir, ".traces"); + + if ((EC = sys::fs::remove_directories(TraceDir))) { + + ErrMsg() << "Failed to remove existing trace directory in `" << OutputDir + << "`: " << EC.message() << '\n'; + return 1; + + } + + if ((EC = sys::fs::create_directories(TraceDir))) { + + ErrMsg() << "Failed to create output directory `" << OutputDir << "`: " + << EC.message() << '\n'; + return 1; + + } + // ------------------------------------------------------------------------ // // Traverse corpus directory // -- cgit v1.2.3 From 1afa0d78619e57fcdfbc19d9cfa37256962dea59 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Sat, 24 Jul 2021 23:31:06 +0000 Subject: optimin: add test of binary target --- utils/optimin/src/OptiMin.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 8d839911..84179022 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -94,6 +94,7 @@ static std::chrono::seconds Duration; static std::string AFLShowmapPath; static bool TargetArgsHasAtAt = false; static bool KeepTraces = false; +static bool SkipBinCheck = false; static const auto ErrMsg = [] { @@ -183,12 +184,14 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { } -static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { +static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov, + bool BinCheck = false) { Optional Redirects[] = {None, None, None}; SmallString<32> TracePath{OutputDir}; - sys::path::append(TracePath, ".traces", sys::path::filename(Seed)); + StringRef TraceName = BinCheck ? ".run_test" : sys::path::filename(Seed); + sys::path::append(TracePath, ".traces", TraceName); // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ @@ -238,7 +241,7 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov) { } - if (!KeepTraces) sys::fs::remove(TracePath); + if (!KeepTraces || BinCheck) sys::fs::remove(TracePath); return Error::success(); } @@ -281,6 +284,7 @@ int main(int argc, char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "Optimal corpus minimizer"); KeepTraces = !!std::getenv("AFL_KEEP_TRACES"); + SkipBinCheck = !!std::getenv("AFL_SKIP_BIN_CHECK"); const auto AFLPath = std::getenv("AFL_PATH"); for (const auto &Arg : TargetArgs) @@ -404,6 +408,29 @@ int main(int argc, char *argv[]) { EndTimer(/*ShowProgBar=*/false); + // ------------------------------------------------------------------------ // + // Test the target binary + // ------------------------------------------------------------------------ // + + AFLCoverageVector Cov; + + if (!SkipBinCheck && SeedFiles.size() > 0) { + + StatMsg() << "Testing the target binary... "; + StartTimer(/*ShowProgBar=*/false); + + if (auto Err = getAFLCoverage(SeedFiles.front(), Cov, /*BinCheck=*/true)) { + + ErrMsg() << "No instrumentation output detected (perhaps crash or timeout)"; + return 1; + + } + + EndTimer(/*ShowProgBar=*/false); + SuccMsg() << "OK, " << Cov.size() << " tuples recorded\n"; + + } + // ------------------------------------------------------------------------ // // Generate seed coverage // @@ -422,7 +449,6 @@ int main(int argc, char *argv[]) { EvalMaxSAT Solver(/*nbMinimizeThread=*/0); MaxSATSeeds SeedVars; MaxSATCoverageMap SeedCoverage; - AFLCoverageVector Cov; for (const auto &SeedFile : SeedFiles) { -- cgit v1.2.3 From 33f9f911c13cfd513366b7b1c9f9c66c0aa944f7 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Sat, 24 Jul 2021 23:37:28 +0000 Subject: optimin: fix default timeout So that it matches the help text --- utils/optimin/README.md | 2 +- utils/optimin/src/OptiMin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/optimin/README.md b/utils/optimin/README.md index 3036b449..c6f2af06 100644 --- a/utils/optimin/README.md +++ b/utils/optimin/README.md @@ -40,7 +40,7 @@ General options: -m megs - Memory limit for child process (default=none) -o dir - Output directory -p - Display progress bar - -t msec - Run time limit for child process (default=none) + -t msec - Run time limit for child process (default=5000) -w csv - Weights file Generic Options: diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 84179022..4f88b897 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -142,7 +142,7 @@ static cl::opt MemLimit( cl::value_desc("megs"), cl::init("none")); static cl::opt Timeout( "t", cl::desc("Run time limit for child process (default=5000)"), - cl::value_desc("msec"), cl::init("4000")); + cl::value_desc("msec"), cl::init("5000")); static cl::opt CrashMode( "C", cl::desc("Keep crashing inputs, reject everything else")); -- cgit v1.2.3 From cc933bcc0c63df22df981ef991582170d40fbb95 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Mon, 26 Jul 2021 02:11:21 +0000 Subject: optimin: support afl-cmin crash mode --- utils/optimin/src/OptiMin.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 4f88b897..276f6b0f 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -212,9 +212,14 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov, // Run afl-showmap const int RC = sys::ExecuteAndWait(AFLShowmapPath, AFLShowmapArgs, /*env=*/None, Redirects); - if (RC) + if (RC && !CrashMode) { + + ErrMsg() << "Exit code " << RC << " != 0 received from afl-showmap"; + sys::fs::remove(TracePath); return createStringError(inconvertibleErrorCode(), "afl-showmap failed"); + } + // Parse afl-showmap output const auto CovOrErr = MemoryBuffer::getFile(TracePath); if (const auto EC = CovOrErr.getError()) { @@ -287,6 +292,8 @@ int main(int argc, char *argv[]) { SkipBinCheck = !!std::getenv("AFL_SKIP_BIN_CHECK"); const auto AFLPath = std::getenv("AFL_PATH"); + if (CrashMode) ::setenv("AFL_CMIN_CRASHES_ONLY", "1", /*overwrite=*/true); + for (const auto &Arg : TargetArgs) if (Arg == "@@") TargetArgsHasAtAt = true; @@ -354,8 +361,8 @@ int main(int argc, char *argv[]) { if ((EC = sys::fs::create_directories(TraceDir))) { - ErrMsg() << "Failed to create output directory `" << OutputDir << "`: " - << EC.message() << '\n'; + ErrMsg() << "Failed to create output directory `" << OutputDir + << "`: " << EC.message() << '\n'; return 1; } @@ -421,7 +428,8 @@ int main(int argc, char *argv[]) { if (auto Err = getAFLCoverage(SeedFiles.front(), Cov, /*BinCheck=*/true)) { - ErrMsg() << "No instrumentation output detected (perhaps crash or timeout)"; + ErrMsg() + << "No instrumentation output detected (perhaps crash or timeout)"; return 1; } @@ -456,8 +464,8 @@ int main(int argc, char *argv[]) { Cov.clear(); if (auto Err = getAFLCoverage(SeedFile, Cov)) { - ErrMsg() << "Failed to get coverage for seed `" << SeedFile << "`: " - << Err << '\n'; + ErrMsg() << "Failed to get coverage for seed `" << SeedFile + << "`: " << Err << '\n'; return 1; } -- cgit v1.2.3 From 036282185b0f06df7b7ba354f41159d682853008 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 28 Jul 2021 04:40:43 +0000 Subject: optimin: run showmap with an entire input directory Rather than executing with one seed at a time. This required disabling the target binary test (for now). --- utils/optimin/src/OptiMin.cpp | 295 +++++++++++++++++++++++++----------------- 1 file changed, 179 insertions(+), 116 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 276f6b0f..242eeea9 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -64,7 +64,10 @@ using AFLTuple = std::pair; /// Coverage for a given seed file using AFLCoverageVector = std::vector; -/// Maps seed file paths to a weight +/// Map seed file paths to its coverage vector +using AFLCoverageMap = StringMap; + +/// Map seed file paths to a weight using WeightsMap = StringMap; /// A seed identifier in the MaxSAT solver @@ -88,6 +91,9 @@ using MaxSATCoverageMap = DenseMap; // `afl-showmap.c` static constexpr uint32_t MAX_EDGE_FREQ = 8; +// The maximum number of failures allowed when parsing a weights file +static constexpr unsigned MAX_WEIGHT_FAILURES = 5; + static sys::TimePoint<> StartTime, EndTime; static std::chrono::seconds Duration; @@ -98,30 +104,30 @@ static bool SkipBinCheck = false; static const auto ErrMsg = [] { - return WithColor(errs(), HighlightColor::Error) << "[-] "; + return WithColor(errs(), raw_ostream::RED, /*Bold=*/true) << "[-] "; }; static const auto WarnMsg = [] { - return WithColor(errs(), HighlightColor::Warning) << "[-] "; + return WithColor(errs(), raw_ostream::MAGENTA, /*Bold=*/true) << "[-] "; }; static const auto SuccMsg = [] { - return WithColor(outs(), HighlightColor::String) << "[+] "; + return WithColor(outs(), raw_ostream::GREEN, /*Bold=*/true) << "[+] "; }; static const auto StatMsg = [] { - return WithColor(outs(), HighlightColor::Remark) << "[*] "; + return WithColor(outs(), raw_ostream::BLUE, /*Bold=*/true) << "[*] "; }; -static cl::opt CorpusDir("i", cl::desc("Input directory"), - cl::value_desc("dir"), cl::Required); +static cl::opt InputDir("i", cl::desc("Input directory"), + cl::value_desc("dir"), cl::Required); static cl::opt OutputDir("o", cl::desc("Output directory"), cl::value_desc("dir"), cl::Required); @@ -164,6 +170,7 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { SmallVector Lines; MB.getBuffer().trim().split(Lines, '\n'); + unsigned FailureCount = 0; unsigned Weight = 0; for (const auto &Line : Lines) { @@ -176,7 +183,13 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { } else { - WarnMsg() << "Failed to read weight for `" << Seed << "`. Skipping...\n"; + if (FailureCount >= MAX_WEIGHT_FAILURES) { + ErrMsg() << "Too many failures. Aborting\n"; + std::exit(1); + } + + WarnMsg() << "Failed to read weight for '" << Seed << "'. Skipping...\n"; + FailureCount++; } @@ -184,23 +197,52 @@ static void GetWeights(const MemoryBuffer &MB, WeightsMap &Weights) { } -static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov, - bool BinCheck = false) { +static std::error_code readCov(const StringRef Trace, AFLCoverageVector &Cov) { + + const auto CovOrErr = MemoryBuffer::getFile(Trace); + if (const auto EC = CovOrErr.getError()) return EC; + + SmallVector Lines; + CovOrErr.get()->getBuffer().trim().split(Lines, '\n'); + + AFLTupleID Edge = 0; + unsigned Freq = 0; + + for (const auto &Line : Lines) { + + const auto &[EdgeStr, FreqStr] = Line.split(':'); + + to_integer(EdgeStr, Edge, 10); + to_integer(FreqStr, Freq, 10); + Cov.push_back({Edge, Freq}); + + } + + return std::error_code(); + +} + +static Error runShowmap(AFLCoverageMap &CovMap) { Optional Redirects[] = {None, None, None}; - SmallString<32> TracePath{OutputDir}; - StringRef TraceName = BinCheck ? ".run_test" : sys::path::filename(Seed); - sys::path::append(TracePath, ".traces", TraceName); + SmallString<32> TraceDir{OutputDir}; + sys::path::append(TraceDir, ".traces"); + + SmallString<32> StdinFile{TraceDir}; + sys::path::append(StdinFile, ".cur_input"); // Prepare afl-showmap arguments SmallVector AFLShowmapArgs{ - AFLShowmapPath, "-m", MemLimit, "-t", Timeout, "-q", "-o", TracePath}; + AFLShowmapPath, "-m", MemLimit, "-t", Timeout, + "-q", "-i", InputDir, "-o", TraceDir}; - if (TargetArgsHasAtAt) - AFLShowmapArgs.append({"-A", Seed}); - else - Redirects[/* stdin */ 0] = Seed; + if (TargetArgsHasAtAt) { + + AFLShowmapArgs.append({"-A", StdinFile}); + Redirects[/* stdin */ 0] = "/dev/null"; + + } if (FridaMode) AFLShowmapArgs.push_back("-O"); if (QemuMode) AFLShowmapArgs.push_back("-Q"); @@ -214,39 +256,48 @@ static Error getAFLCoverage(const StringRef Seed, AFLCoverageVector &Cov, /*env=*/None, Redirects); if (RC && !CrashMode) { - ErrMsg() << "Exit code " << RC << " != 0 received from afl-showmap"; - sys::fs::remove(TracePath); + ErrMsg() << "Exit code " << RC << " != 0 received from afl-showmap\n"; + sys::fs::remove_directories(TraceDir); return createStringError(inconvertibleErrorCode(), "afl-showmap failed"); } // Parse afl-showmap output - const auto CovOrErr = MemoryBuffer::getFile(TracePath); - if (const auto EC = CovOrErr.getError()) { + AFLCoverageVector Cov; + std::error_code EC; + sys::fs::file_status Status; - sys::fs::remove(TracePath); - return createStringError(EC, "Failed to read afl-showmap output file `%s`", - TracePath.c_str()); + for (sys::fs::recursive_directory_iterator Dir(TraceDir, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { - } + if (EC) return errorCodeToError(EC); - SmallVector Lines; - CovOrErr.get()->getBuffer().trim().split(Lines, '\n'); + const auto &Path = Dir->path(); + if ((EC = sys::fs::status(Path, Status))) return errorCodeToError(EC); - AFLTupleID Edge = 0; - unsigned Freq = 0; + switch (Status.type()) { - for (const auto &Line : Lines) { + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + Cov.clear(); + if ((EC = readCov(Path, Cov))) { - const auto &[EdgeStr, FreqStr] = Line.split(':'); + sys::fs::remove(Path); + return errorCodeToError(EC); - to_integer(EdgeStr, Edge, 10); - to_integer(FreqStr, Freq, 10); - Cov.push_back({Edge, Freq}); + } + + CovMap.try_emplace(sys::path::filename(Path), Cov); + default: + /* Ignore */ + break; + + } } - if (!KeepTraces || BinCheck) sys::fs::remove(TracePath); + if (!KeepTraces) sys::fs::remove_directories(TraceDir); return Error::success(); } @@ -326,14 +377,14 @@ int main(int argc, char *argv[]) { if (WeightsFile != "") { - StatMsg() << "Reading weights from `" << WeightsFile << "`... "; + StatMsg() << "Reading weights from '" << WeightsFile << "'... "; StartTimer(/*ShowProgBar=*/false); const auto WeightsOrErr = MemoryBuffer::getFile(WeightsFile); if ((EC = WeightsOrErr.getError())) { - ErrMsg() << "Failed to read weights from `" << WeightsFile - << "`: " << EC.message() << '\n'; + ErrMsg() << "Failed to read weights from '" << WeightsFile + << "': " << EC.message() << '\n'; return 1; } @@ -345,47 +396,33 @@ int main(int argc, char *argv[]) { } // ------------------------------------------------------------------------ // - // Setup output directory + // Traverse input directory + // + // Find the seed files inside this directory (and subdirectories). // ------------------------------------------------------------------------ // - SmallString<32> TraceDir{OutputDir}; - sys::path::append(TraceDir, ".traces"); - - if ((EC = sys::fs::remove_directories(TraceDir))) { - - ErrMsg() << "Failed to remove existing trace directory in `" << OutputDir - << "`: " << EC.message() << '\n'; - return 1; - - } + StatMsg() << "Locating seeds in '" << InputDir << "'... "; + StartTimer(/*ShowProgBar=*/false); - if ((EC = sys::fs::create_directories(TraceDir))) { + bool IsDirResult; + if ((EC = sys::fs::is_directory(InputDir, IsDirResult))) { - ErrMsg() << "Failed to create output directory `" << OutputDir - << "`: " << EC.message() << '\n'; + ErrMsg() << "Invalid input directory '" << InputDir + << "': " << EC.message() << '\n'; return 1; } - // ------------------------------------------------------------------------ // - // Traverse corpus directory - // - // Find the seed files inside this directory. - // ------------------------------------------------------------------------ // - - StatMsg() << "Locating seeds in `" << CorpusDir << "`... "; - StartTimer(/*ShowProgBar=*/false); - - std::vector SeedFiles; - sys::fs::file_status Status; + sys::fs::file_status Status; + StringMap SeedFiles; - for (sys::fs::recursive_directory_iterator Dir(CorpusDir, EC), DirEnd; + for (sys::fs::recursive_directory_iterator Dir(InputDir, EC), DirEnd; Dir != DirEnd && !EC; Dir.increment(EC)) { if (EC) { - ErrMsg() << "Failed to traverse corpus directory `" << CorpusDir - << "`: " << EC.message() << '\n'; + ErrMsg() << "Failed to traverse input directory '" << InputDir + << "': " << EC.message() << '\n'; return 1; } @@ -393,21 +430,22 @@ int main(int argc, char *argv[]) { const auto &Path = Dir->path(); if ((EC = sys::fs::status(Path, Status))) { - WarnMsg() << "Failed to access seed file `" << Path - << "`: " << EC.message() << ". Skipping...\n"; - continue; + ErrMsg() << "Failed to access '" << Path << "': " << EC.message() + << '\n'; + return 1; } switch (Status.type()) { - case sys::fs::file_type::regular_file: - case sys::fs::file_type::symlink_file: - case sys::fs::file_type::type_unknown: - SeedFiles.push_back(Path); - default: - /* Ignore */ - break; + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + SeedFiles.try_emplace(sys::path::filename(Path), + sys::path::parent_path(Path)); + default: + /* Ignore */ + break; } @@ -415,24 +453,55 @@ int main(int argc, char *argv[]) { EndTimer(/*ShowProgBar=*/false); + if (SeedFiles.empty()) { + + ErrMsg() << "Failed to find any seed files in '" << InputDir << "'\n"; + return 1; + + } + + // ------------------------------------------------------------------------ // + // Setup output directory + // ------------------------------------------------------------------------ // + + SmallString<32> TraceDir{OutputDir}; + sys::path::append(TraceDir, ".traces"); + + if ((EC = sys::fs::remove_directories(TraceDir))) { + + ErrMsg() << "Failed to remove existing trace directory in '" << OutputDir + << "': " << EC.message() << '\n'; + return 1; + + } + + if ((EC = sys::fs::create_directories(TraceDir))) { + + ErrMsg() << "Failed to create output directory '" << OutputDir + << "': " << EC.message() << '\n'; + return 1; + + } + // ------------------------------------------------------------------------ // // Test the target binary // ------------------------------------------------------------------------ // AFLCoverageVector Cov; - if (!SkipBinCheck && SeedFiles.size() > 0) { + if (!SkipBinCheck) { StatMsg() << "Testing the target binary... "; StartTimer(/*ShowProgBar=*/false); - if (auto Err = getAFLCoverage(SeedFiles.front(), Cov, /*BinCheck=*/true)) { - - ErrMsg() - << "No instrumentation output detected (perhaps crash or timeout)"; - return 1; - - } + // if (auto Err = runShowmap(TestSeed, Cov, /*BinCheck=*/true)) { + // + // ErrMsg() + // << "No instrumentation output detected (perhaps crash or + // timeout)"; + // return 1; + // + // } EndTimer(/*ShowProgBar=*/false); SuccMsg() << "OK, " << Cov.size() << " tuples recorded\n"; @@ -447,35 +516,28 @@ int main(int argc, char *argv[]) { // then store this coverage information in the appropriate data structures. // ------------------------------------------------------------------------ // - size_t SeedCount = 0; - const size_t NumSeeds = SeedFiles.size(); - - if (!ShowProgBar) - StatMsg() << "Generating coverage for " << NumSeeds << " seeds... "; - StartTimer(ShowProgBar); + StatMsg() << "Running afl-showmap on " << SeedFiles.size() << " seeds...\n"; + StartTimer(/*ShowProgBar=*/false); - EvalMaxSAT Solver(/*nbMinimizeThread=*/0); + AFLCoverageMap CovMap; MaxSATSeeds SeedVars; MaxSATCoverageMap SeedCoverage; + EvalMaxSAT Solver(/*nbMinimizeThread=*/0); - for (const auto &SeedFile : SeedFiles) { - - // Execute seed - Cov.clear(); - if (auto Err = getAFLCoverage(SeedFile, Cov)) { + if (auto Err = runShowmap(CovMap)) { - ErrMsg() << "Failed to get coverage for seed `" << SeedFile - << "`: " << Err << '\n'; - return 1; + ErrMsg() << "Failed to generate coverage: " << Err << '\n'; + return 1; - } + } + for (const auto &SeedCov : CovMap) { // Create a variable to represent the seed const SeedID Var = Solver.newVar(); - SeedVars.push_back({Var, SeedFile}); + SeedVars.emplace_back(Var, SeedCov.first()); // Record the set of seeds that cover a particular edge - for (const auto &[Edge, Freq] : Cov) { + for (auto &[Edge, Freq] : SeedCov.second) { if (EdgesOnly) { @@ -492,12 +554,10 @@ int main(int argc, char *argv[]) { } - if ((++SeedCount % 10 == 0) && ShowProgBar) - ProgBar.update(SeedCount * 100 / NumSeeds, "Generating seed coverage"); - } - EndTimer(ShowProgBar); + SuccMsg() << "afl-showmap completed in "; + EndTimer(/*ShowProgBar=*/false); // ------------------------------------------------------------------------ // // Set the hard and soft constraints in the solver @@ -506,7 +566,7 @@ int main(int argc, char *argv[]) { if (!ShowProgBar) StatMsg() << "Generating constraints... "; StartTimer(ShowProgBar); - SeedCount = 0; + size_t SeedCount = 0; // Ensure that at least one seed is selected that covers a particular edge // (hard constraint) @@ -552,7 +612,7 @@ int main(int argc, char *argv[]) { // ------------------------------------------------------------------------ // SmallVector Solution; - SmallString<32> OutputSeed; + SmallString<32> InputSeed, OutputSeed; if (Solved) { @@ -561,28 +621,31 @@ int main(int argc, char *argv[]) { } else { - ErrMsg() << "Failed to find an optimal solution for `" << CorpusDir - << "`\n"; + ErrMsg() << "Failed to find an optimal solution for '" << InputDir << "'\n"; return 1; } SuccMsg() << "Minimized corpus size: " << Solution.size() << " seeds\n"; - if (!ShowProgBar) StatMsg() << "Copying to `" << OutputDir << "`... "; + if (!ShowProgBar) StatMsg() << "Copying to '" << OutputDir << "'... "; StartTimer(ShowProgBar); SeedCount = 0; for (const auto &Seed : Solution) { + InputSeed = SeedFiles[Seed]; + sys::path::append(InputSeed, Seed); + OutputSeed = OutputDir; - sys::path::append(OutputSeed, sys::path::filename(Seed)); + sys::path::append(OutputSeed, Seed); - if ((EC = sys::fs::copy_file(Seed, OutputSeed))) { + if ((EC = sys::fs::copy_file(InputSeed, OutputSeed))) { - WarnMsg() << "Failed to copy `" << Seed << "` to `" << OutputDir - << "`: " << EC.message() << '\n'; + ErrMsg() << "Failed to copy '" << Seed << "' to '" << OutputDir + << "': " << EC.message() << '\n'; + return 1; } -- cgit v1.2.3 From 0dbd37a20b90284201a117192d126cbeee998663 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 28 Jul 2021 04:47:20 +0000 Subject: optimin: removed progress bar It was hard to get working with showmap's directory mode --- utils/optimin/src/OptiMin.cpp | 62 ++++++++++++++--------------------- utils/optimin/src/ProgressBar.h | 71 ----------------------------------------- 2 files changed, 24 insertions(+), 109 deletions(-) delete mode 100644 utils/optimin/src/ProgressBar.h (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 242eeea9..4f0cb4f7 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -23,7 +23,6 @@ #include #include "EvalMaxSAT.h" -#include "ProgressBar.h" using namespace llvm; @@ -131,7 +130,6 @@ static cl::opt InputDir("i", cl::desc("Input directory"), static cl::opt OutputDir("o", cl::desc("Output directory"), cl::value_desc("dir"), cl::Required); -static cl::opt ShowProgBar("p", cl::desc("Display progress bar")); static cl::opt EdgesOnly("f", cl::desc("Include edge hit counts"), cl::init(true)); static cl::opt WeightsFile("w", cl::desc("Weights file"), @@ -302,22 +300,19 @@ static Error runShowmap(AFLCoverageMap &CovMap) { } -static inline void StartTimer(bool ShowProgBar) { +static inline void StartTimer() { StartTime = std::chrono::system_clock::now(); } -static inline void EndTimer(bool ShowProgBar) { +static inline void EndTimer() { EndTime = std::chrono::system_clock::now(); Duration = std::chrono::duration_cast(EndTime - StartTime); - if (ShowProgBar) - outs() << '\n'; - else - outs() << Duration.count() << "s\n"; + SuccMsg() << " Completed in " << Duration.count() << " s\n"; } @@ -328,7 +323,6 @@ static inline void EndTimer(bool ShowProgBar) { int main(int argc, char *argv[]) { WeightsMap Weights; - ProgressBar ProgBar; std::error_code EC; // ------------------------------------------------------------------------ // @@ -377,8 +371,8 @@ int main(int argc, char *argv[]) { if (WeightsFile != "") { - StatMsg() << "Reading weights from '" << WeightsFile << "'... "; - StartTimer(/*ShowProgBar=*/false); + StatMsg() << "Reading weights from '" << WeightsFile << "'...\n"; + StartTimer(); const auto WeightsOrErr = MemoryBuffer::getFile(WeightsFile); if ((EC = WeightsOrErr.getError())) { @@ -391,7 +385,7 @@ int main(int argc, char *argv[]) { GetWeights(*WeightsOrErr.get(), Weights); - EndTimer(/*ShowProgBar=*/false); + EndTimer(); } @@ -401,8 +395,8 @@ int main(int argc, char *argv[]) { // Find the seed files inside this directory (and subdirectories). // ------------------------------------------------------------------------ // - StatMsg() << "Locating seeds in '" << InputDir << "'... "; - StartTimer(/*ShowProgBar=*/false); + StatMsg() << "Locating seeds in '" << InputDir << "'...\n"; + StartTimer(); bool IsDirResult; if ((EC = sys::fs::is_directory(InputDir, IsDirResult))) { @@ -451,7 +445,7 @@ int main(int argc, char *argv[]) { } - EndTimer(/*ShowProgBar=*/false); + EndTimer(); if (SeedFiles.empty()) { @@ -491,8 +485,8 @@ int main(int argc, char *argv[]) { if (!SkipBinCheck) { - StatMsg() << "Testing the target binary... "; - StartTimer(/*ShowProgBar=*/false); + StatMsg() << "Testing the target binary...\n"; + StartTimer(); // if (auto Err = runShowmap(TestSeed, Cov, /*BinCheck=*/true)) { // @@ -503,7 +497,7 @@ int main(int argc, char *argv[]) { // // } - EndTimer(/*ShowProgBar=*/false); + EndTimer(); SuccMsg() << "OK, " << Cov.size() << " tuples recorded\n"; } @@ -517,7 +511,7 @@ int main(int argc, char *argv[]) { // ------------------------------------------------------------------------ // StatMsg() << "Running afl-showmap on " << SeedFiles.size() << " seeds...\n"; - StartTimer(/*ShowProgBar=*/false); + StartTimer(); AFLCoverageMap CovMap; MaxSATSeeds SeedVars; @@ -557,14 +551,14 @@ int main(int argc, char *argv[]) { } SuccMsg() << "afl-showmap completed in "; - EndTimer(/*ShowProgBar=*/false); + EndTimer(); // ------------------------------------------------------------------------ // // Set the hard and soft constraints in the solver // ------------------------------------------------------------------------ // - if (!ShowProgBar) StatMsg() << "Generating constraints... "; - StartTimer(ShowProgBar); + StatMsg() << "Generating constraints...\n"; + StartTimer(); size_t SeedCount = 0; @@ -581,10 +575,6 @@ int main(int argc, char *argv[]) { Solver.addClause(Clauses); - if ((++SeedCount % 10 == 0) && ShowProgBar) - ProgBar.update(SeedCount * 100 / SeedCoverage.size(), - "Generating clauses"); - } // Select the minimum number of seeds that cover a particular set of edges @@ -592,18 +582,18 @@ int main(int argc, char *argv[]) { for (const auto &[Var, Seed] : SeedVars) Solver.addWeightedClause({-Var}, Weights[sys::path::filename(Seed)]); - EndTimer(ShowProgBar); + EndTimer(); // ------------------------------------------------------------------------ // // Generate a solution // ------------------------------------------------------------------------ // - StatMsg() << "Solving... "; - StartTimer(/*ShowProgBar=*/false); + StatMsg() << "Solving...\n"; + StartTimer(); const bool Solved = Solver.solve(); - EndTimer(/*ShowProgBar=*/false); + EndTimer(); // ------------------------------------------------------------------------ // // Save the solution @@ -626,10 +616,9 @@ int main(int argc, char *argv[]) { } - SuccMsg() << "Minimized corpus size: " << Solution.size() << " seeds\n"; - - if (!ShowProgBar) StatMsg() << "Copying to '" << OutputDir << "'... "; - StartTimer(ShowProgBar); + StatMsg() << "Copying " << Solution.size() << " seeds to '" + << OutputDir << "'...\n"; + StartTimer(); SeedCount = 0; @@ -649,12 +638,9 @@ int main(int argc, char *argv[]) { } - if ((++SeedCount % 10 == 0) && ShowProgBar) - ProgBar.update(SeedCount * 100 / Solution.size(), "Copying seeds"); - } - EndTimer(ShowProgBar); + EndTimer(); SuccMsg() << "Done!\n"; return 0; diff --git a/utils/optimin/src/ProgressBar.h b/utils/optimin/src/ProgressBar.h deleted file mode 100644 index 9b75594b..00000000 --- a/utils/optimin/src/ProgressBar.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Progress bar. - * - * Adapted from https://www.bfilipek.com/2020/02/inidicators.html - */ - -#pragma once - -#include -#include - -/// Display a progress bar in the terminal -class ProgressBar { - - private: - const size_t BarWidth; - const std::string Fill; - const std::string Remainder; - - public: - ProgressBar() : ProgressBar(60, "#", " ") { - - } - - ProgressBar(size_t Width, const llvm::StringRef F, const llvm::StringRef R) - : BarWidth(Width), Fill(F), Remainder(R) { - - } - - void update(float Progress, const llvm::StringRef Status = "", - llvm::raw_ostream &OS = llvm::outs()) { - - // No need to write once progress is 100% - if (Progress > 100.0f) return; - - // Move cursor to the first position on the same line and flush - OS << '\r'; - OS.flush(); - - // Start bar - OS << '['; - - const auto Completed = - static_cast(Progress * static_cast(BarWidth) / 100.0); - for (size_t I = 0; I < BarWidth; ++I) { - - if (I <= Completed) { - - OS << Fill; - - } else { - - OS << Remainder; - - } - - } - - // End bar - OS << ']'; - - // Write progress percentage - OS << ' ' << std::min(static_cast(Progress), size_t(100)) << '%'; - - // Write status text - OS << " " << Status; - - } - -}; - -- cgit v1.2.3 From 0bd6fda98b4d376d40a87d5efb8cc4fa761a453e Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 28 Jul 2021 06:44:25 +0000 Subject: optimin: add target test back in --- utils/optimin/src/OptiMin.cpp | 183 +++++++++++++++++++++++++++--------------- 1 file changed, 118 insertions(+), 65 deletions(-) (limited to 'utils') diff --git a/utils/optimin/src/OptiMin.cpp b/utils/optimin/src/OptiMin.cpp index 4f0cb4f7..ce1fb850 100644 --- a/utils/optimin/src/OptiMin.cpp +++ b/utils/optimin/src/OptiMin.cpp @@ -96,7 +96,7 @@ static constexpr unsigned MAX_WEIGHT_FAILURES = 5; static sys::TimePoint<> StartTime, EndTime; static std::chrono::seconds Duration; -static std::string AFLShowmapPath; +static std::string ShowmapPath; static bool TargetArgsHasAtAt = false; static bool KeepTraces = false; static bool SkipBinCheck = false; @@ -220,82 +220,133 @@ static std::error_code readCov(const StringRef Trace, AFLCoverageVector &Cov) { } -static Error runShowmap(AFLCoverageMap &CovMap) { +static Error runShowmap(AFLCoverageMap &CovMap, const StringRef Input, + bool BinCheck = false) { + const bool InputIsFile = !sys::fs::is_directory(Input); Optional Redirects[] = {None, None, None}; SmallString<32> TraceDir{OutputDir}; sys::path::append(TraceDir, ".traces"); + SmallString<32> Output{TraceDir}; SmallString<32> StdinFile{TraceDir}; - sys::path::append(StdinFile, ".cur_input"); + // ------------------------------------------------------------------------ // // Prepare afl-showmap arguments - SmallVector AFLShowmapArgs{ - AFLShowmapPath, "-m", MemLimit, "-t", Timeout, - "-q", "-i", InputDir, "-o", TraceDir}; + // + // If the given input is a file, then feed this directly into stdin. + // Otherwise, if it is a directory, specify this on the afl-showmap command + // line. + // ------------------------------------------------------------------------ // + + SmallVector ShowmapArgs{ShowmapPath, "-q", + "-m", MemLimit, + "-t", Timeout}; + + if (InputIsFile) { + + StdinFile = Input; + sys::path::append(Output, + BinCheck ? ".run_test" : sys::path::filename(Input)); + + } else { + + sys::path::append(StdinFile, ".cur_input"); + ShowmapArgs.append({"-i", Input}); + + } + if (TargetArgsHasAtAt) { - AFLShowmapArgs.append({"-A", StdinFile}); + ShowmapArgs.append({"-A", StdinFile}); Redirects[/* stdin */ 0] = "/dev/null"; + } else if (InputIsFile) { + + Redirects[/* stdin */ 0] = Input; + } - if (FridaMode) AFLShowmapArgs.push_back("-O"); - if (QemuMode) AFLShowmapArgs.push_back("-Q"); - if (UnicornMode) AFLShowmapArgs.push_back("-U"); + if (FridaMode) ShowmapArgs.push_back("-O"); + if (QemuMode) ShowmapArgs.push_back("-Q"); + if (UnicornMode) ShowmapArgs.push_back("-U"); - AFLShowmapArgs.append({"--", TargetProg}); - AFLShowmapArgs.append(TargetArgs.begin(), TargetArgs.end()); + ShowmapArgs.append({"-o", Output, "--", TargetProg}); + ShowmapArgs.append(TargetArgs.begin(), TargetArgs.end()); + // ------------------------------------------------------------------------ // // Run afl-showmap - const int RC = sys::ExecuteAndWait(AFLShowmapPath, AFLShowmapArgs, + // ------------------------------------------------------------------------ // + + const int RC = sys::ExecuteAndWait(ShowmapPath, ShowmapArgs, /*env=*/None, Redirects); if (RC && !CrashMode) { ErrMsg() << "Exit code " << RC << " != 0 received from afl-showmap\n"; - sys::fs::remove_directories(TraceDir); return createStringError(inconvertibleErrorCode(), "afl-showmap failed"); } + // ------------------------------------------------------------------------ // // Parse afl-showmap output + // ------------------------------------------------------------------------ // + AFLCoverageVector Cov; std::error_code EC; sys::fs::file_status Status; - for (sys::fs::recursive_directory_iterator Dir(TraceDir, EC), DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { + if (InputIsFile) { - if (EC) return errorCodeToError(EC); + // Read a single output coverage file + if ((EC = readCov(Output, Cov))) { - const auto &Path = Dir->path(); - if ((EC = sys::fs::status(Path, Status))) return errorCodeToError(EC); + sys::fs::remove(Output); + return errorCodeToError(EC); - switch (Status.type()) { + } - case sys::fs::file_type::regular_file: - case sys::fs::file_type::symlink_file: - case sys::fs::file_type::type_unknown: - Cov.clear(); - if ((EC = readCov(Path, Cov))) { + CovMap.try_emplace(sys::path::filename(Input), Cov); + if (!KeepTraces) sys::fs::remove(Output); - sys::fs::remove(Path); - return errorCodeToError(EC); + } else { - } + // Read a directory of output coverage files + for (sys::fs::recursive_directory_iterator Dir(TraceDir, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { - CovMap.try_emplace(sys::path::filename(Path), Cov); - default: - /* Ignore */ - break; + if (EC) return errorCodeToError(EC); + + const auto &Path = Dir->path(); + if ((EC = sys::fs::status(Path, Status))) return errorCodeToError(EC); + + switch (Status.type()) { + + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + Cov.clear(); + if ((EC = readCov(Path, Cov))) { + + sys::fs::remove(Path); + return errorCodeToError(EC); + + } + + CovMap.try_emplace(sys::path::filename(Path), Cov); + default: + // Ignore + break; + + } } + if (!KeepTraces) sys::fs::remove_directories(TraceDir); + } - if (!KeepTraces) sys::fs::remove_directories(TraceDir); return Error::success(); } @@ -352,15 +403,15 @@ int main(int argc, char *argv[]) { SplitString(PathEnv, EnvPaths, ":"); if (AFLPath) EnvPaths.push_back(AFLPath); - const auto AFLShowmapOrErr = sys::findProgramByName("afl-showmap", EnvPaths); - if (AFLShowmapOrErr.getError()) { + const auto ShowmapOrErr = sys::findProgramByName("afl-showmap", EnvPaths); + if (ShowmapOrErr.getError()) { ErrMsg() << "Failed to find afl-showmap. Check your PATH\n"; return 1; } - AFLShowmapPath = *AFLShowmapOrErr; + ShowmapPath = *ShowmapOrErr; // ------------------------------------------------------------------------ // // Parse weights @@ -401,13 +452,13 @@ int main(int argc, char *argv[]) { bool IsDirResult; if ((EC = sys::fs::is_directory(InputDir, IsDirResult))) { - ErrMsg() << "Invalid input directory '" << InputDir - << "': " << EC.message() << '\n'; + ErrMsg() << "Invalid input directory '" << InputDir << "': " << EC.message() + << '\n'; return 1; } - sys::fs::file_status Status; + sys::fs::file_status Status; StringMap SeedFiles; for (sys::fs::recursive_directory_iterator Dir(InputDir, EC), DirEnd; @@ -424,22 +475,21 @@ int main(int argc, char *argv[]) { const auto &Path = Dir->path(); if ((EC = sys::fs::status(Path, Status))) { - ErrMsg() << "Failed to access '" << Path << "': " << EC.message() - << '\n'; + ErrMsg() << "Failed to access '" << Path << "': " << EC.message() << '\n'; return 1; } switch (Status.type()) { - case sys::fs::file_type::regular_file: - case sys::fs::file_type::symlink_file: - case sys::fs::file_type::type_unknown: - SeedFiles.try_emplace(sys::path::filename(Path), - sys::path::parent_path(Path)); - default: - /* Ignore */ - break; + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + SeedFiles.try_emplace(sys::path::filename(Path), + sys::path::parent_path(Path)); + default: + /* Ignore */ + break; } @@ -481,24 +531,27 @@ int main(int argc, char *argv[]) { // Test the target binary // ------------------------------------------------------------------------ // - AFLCoverageVector Cov; + AFLCoverageMap CovMap; if (!SkipBinCheck) { - StatMsg() << "Testing the target binary...\n"; + const auto It = SeedFiles.begin(); + SmallString<32> TestSeed{It->second}; + sys::path::append(TestSeed, It->first()); + + StatMsg() << "Testing the target binary with '" << TestSeed << "`...\n"; StartTimer(); - // if (auto Err = runShowmap(TestSeed, Cov, /*BinCheck=*/true)) { - // - // ErrMsg() - // << "No instrumentation output detected (perhaps crash or - // timeout)"; - // return 1; - // - // } + if (auto Err = runShowmap(CovMap, TestSeed, /*BinCheck=*/true)) { + + ErrMsg() << "No instrumentation output detected \n"; + return 1; + + } EndTimer(); - SuccMsg() << "OK, " << Cov.size() << " tuples recorded\n"; + SuccMsg() << "OK, " << CovMap.begin()->second.size() + << " tuples recorded\n"; } @@ -513,12 +566,12 @@ int main(int argc, char *argv[]) { StatMsg() << "Running afl-showmap on " << SeedFiles.size() << " seeds...\n"; StartTimer(); - AFLCoverageMap CovMap; MaxSATSeeds SeedVars; MaxSATCoverageMap SeedCoverage; EvalMaxSAT Solver(/*nbMinimizeThread=*/0); - if (auto Err = runShowmap(CovMap)) { + CovMap.clear(); + if (auto Err = runShowmap(CovMap, InputDir)) { ErrMsg() << "Failed to generate coverage: " << Err << '\n'; return 1; @@ -526,6 +579,7 @@ int main(int argc, char *argv[]) { } for (const auto &SeedCov : CovMap) { + // Create a variable to represent the seed const SeedID Var = Solver.newVar(); SeedVars.emplace_back(Var, SeedCov.first()); @@ -550,7 +604,6 @@ int main(int argc, char *argv[]) { } - SuccMsg() << "afl-showmap completed in "; EndTimer(); // ------------------------------------------------------------------------ // @@ -616,8 +669,8 @@ int main(int argc, char *argv[]) { } - StatMsg() << "Copying " << Solution.size() << " seeds to '" - << OutputDir << "'...\n"; + StatMsg() << "Copying " << Solution.size() << " seeds to '" << OutputDir + << "'...\n"; StartTimer(); SeedCount = 0; -- cgit v1.2.3 From 8b66d9503854ab40f7c1fadb26e0a7523ac327e9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Jul 2021 07:12:53 +0200 Subject: frida tool fix --- utils/aflpp_driver/aflpp_driver_test.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'utils') diff --git a/utils/aflpp_driver/aflpp_driver_test.c b/utils/aflpp_driver/aflpp_driver_test.c index fe05b4f8..527ba57b 100644 --- a/utils/aflpp_driver/aflpp_driver_test.c +++ b/utils/aflpp_driver/aflpp_driver_test.c @@ -2,8 +2,6 @@ #include #include -#include "hash.h" - void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) { if (Size < 5) return; -- cgit v1.2.3 From c7a93d50c438e3d6da85232e8d377b838237617b Mon Sep 17 00:00:00 2001 From: DMaroo Date: Fri, 6 Aug 2021 18:40:38 +0530 Subject: Added usage info and command line help flag support TODO: Prevent standalone execution --- utils/plot_ui/afl-plot-ui.c | 166 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 utils/plot_ui/afl-plot-ui.c (limited to 'utils') diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c new file mode 100644 index 00000000..856bf082 --- /dev/null +++ b/utils/plot_ui/afl-plot-ui.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#define WIDTH 400 +#define HEIGHT 640 + +char USAGE[] = + "is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.\n \ +\n \ +Usage:\n \ + -h, --help Show this help menu\n \ +\n \ +NOTE: This utility is not meant to be used standalone. Never run this utility directly. Always run afl-plot, which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag).\n \ +"; + +static void plot_toggled(GtkWidget *caller, gpointer data); + +int main(int argc, char **argv) { + + if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help"))) { + + printf("%s %s", argv[0], USAGE); + return EXIT_SUCCESS; + + } + + GtkWidget *window; + GtkWidget *main_vbox; + + GtkWidget *cbuttons_frame; + GtkWidget *cbuttons_hbox; + + GtkWidget *separator_maj, *separator_min1, *separator_min2, *separator_min3; + + GtkWidget *plots_vbox; + GtkWidget *plot_edges_frame, *plot_exec_speed_frame, *plot_high_freq_frame, + *plot_low_freq_frame; + GtkWidget *plot_edges, *plot_exec_speed, *plot_high_freq, *plot_low_freq; + + gtk_init(&argc, &argv); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(window), WIDTH, HEIGHT); + gtk_window_set_title(GTK_WINDOW(window), "Graph drawing"); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + + cbuttons_frame = gtk_frame_new("Select the plots"); + gtk_container_set_border_width(GTK_CONTAINER(cbuttons_frame), 5); + + cbuttons_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); + + GtkWidget *cbutton_edges, *cbutton_exec_speed, *cbutton_high_freq, + *cbutton_low_freq; + + cbutton_edges = gtk_check_button_new_with_label("Edges"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_edges), TRUE); + g_signal_connect(cbutton_edges, "toggled", G_CALLBACK(plot_toggled), + &plot_edges_frame); + + cbutton_exec_speed = gtk_check_button_new_with_label("Execution Speed"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_exec_speed), TRUE); + g_signal_connect(cbutton_exec_speed, "toggled", G_CALLBACK(plot_toggled), + &plot_exec_speed_frame); + + cbutton_high_freq = gtk_check_button_new_with_label("High Frequency"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_high_freq), TRUE); + g_signal_connect(cbutton_high_freq, "toggled", G_CALLBACK(plot_toggled), + &plot_high_freq_frame); + + cbutton_low_freq = gtk_check_button_new_with_label("Low Frequency"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbutton_low_freq), TRUE); + g_signal_connect(cbutton_low_freq, "toggled", G_CALLBACK(plot_toggled), + &plot_low_freq_frame); + + gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_edges, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_exec_speed, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_high_freq, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(cbuttons_hbox), cbutton_low_freq, TRUE, TRUE, 1); + + gtk_container_add(GTK_CONTAINER(cbuttons_frame), cbuttons_hbox); + gtk_box_pack_start(GTK_BOX(main_vbox), cbuttons_frame, FALSE, TRUE, 1); + + separator_maj = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + gtk_box_pack_start(GTK_BOX(main_vbox), separator_maj, FALSE, TRUE, 1); + + plots_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + + plot_edges_frame = gtk_frame_new("Edges"); + gtk_container_set_border_width(GTK_CONTAINER(plot_edges_frame), 5); + plot_edges = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(plot_edges_frame), plot_edges); + + plot_exec_speed_frame = gtk_frame_new("Exec Speed"); + gtk_container_set_border_width(GTK_CONTAINER(plot_exec_speed_frame), 5); + plot_exec_speed = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(plot_exec_speed_frame), plot_exec_speed); + + plot_high_freq_frame = gtk_frame_new("High Frequency"); + gtk_container_set_border_width(GTK_CONTAINER(plot_high_freq_frame), 5); + plot_high_freq = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(plot_high_freq_frame), plot_high_freq); + + plot_low_freq_frame = gtk_frame_new("Low Frequency"); + gtk_container_set_border_width(GTK_CONTAINER(plot_low_freq_frame), 5); + plot_low_freq = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(plot_low_freq_frame), plot_low_freq); + + separator_min1 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + separator_min2 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + separator_min3 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + + gtk_box_pack_start(GTK_BOX(plots_vbox), plot_edges_frame, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min1, FALSE, TRUE, 1); + + gtk_box_pack_start(GTK_BOX(plots_vbox), plot_exec_speed_frame, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min2, FALSE, TRUE, 1); + + gtk_box_pack_start(GTK_BOX(plots_vbox), plot_high_freq_frame, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min3, FALSE, TRUE, 1); + + gtk_box_pack_start(GTK_BOX(plots_vbox), plot_low_freq_frame, TRUE, TRUE, 1); + + gtk_box_pack_start(GTK_BOX(main_vbox), plots_vbox, TRUE, TRUE, 1); + + gtk_container_add(GTK_CONTAINER(window), main_vbox); + + guint id_edges = gtk_socket_get_id(GTK_SOCKET(plot_edges)); + guint id_exec_speed = gtk_socket_get_id(GTK_SOCKET(plot_exec_speed)); + guint id_high_freq = gtk_socket_get_id(GTK_SOCKET(plot_high_freq)); + guint id_low_freq = gtk_socket_get_id(GTK_SOCKET(plot_low_freq)); + + printf("%x\n%x\n%x\n%x\n", id_edges, id_exec_speed, id_high_freq, + id_low_freq); + + fclose(stdout); + + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), + NULL); + gtk_widget_show_all(window); + gtk_main(); + + return EXIT_SUCCESS; + +} + +static void plot_toggled(GtkWidget *caller, gpointer data) { + + gboolean state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(caller)); + + GtkWidget *widget = *(GtkWidget **)data; + + if (state) { + + gtk_widget_show(widget); + + } else { + + gtk_widget_hide(widget); + + } + +} -- cgit v1.2.3 From 6f3e63de0507647719f64eec7df99f2e2f98d123 Mon Sep 17 00:00:00 2001 From: DMaroo Date: Fri, 6 Aug 2021 18:41:55 +0530 Subject: Added Makefile for building and installing afl-plot-ui Currently, it offers make and make clean functionality only --- utils/plot_ui/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 utils/plot_ui/Makefile (limited to 'utils') diff --git a/utils/plot_ui/Makefile b/utils/plot_ui/Makefile new file mode 100644 index 00000000..7ade8a40 --- /dev/null +++ b/utils/plot_ui/Makefile @@ -0,0 +1,10 @@ +CFLAGS=`pkg-config --cflags gtk+-3.0` +LDFLAGS=`pkg-config --libs gtk+-3.0` + +all: afl-plot-ui + +afl-plot-ui: afl-plot-ui.c + $(CC) $(CFLAGS) -o afl-plot-ui afl-plot-ui.c $(LDFLAGS) + +clean: + rm -f afl-plot-ui \ No newline at end of file -- cgit v1.2.3 From 7bedd862d374c4292d72e5ce8211b425b1d6ddf2 Mon Sep 17 00:00:00 2001 From: DMaroo Date: Fri, 6 Aug 2021 18:42:49 +0530 Subject: Added README to describe the working of afl-plot-ui --- utils/plot_ui/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 utils/plot_ui/README.md (limited to 'utils') diff --git a/utils/plot_ui/README.md b/utils/plot_ui/README.md new file mode 100644 index 00000000..d8afa09f --- /dev/null +++ b/utils/plot_ui/README.md @@ -0,0 +1,5 @@ +# afl-plot-ui + +`afl-plot-ui` is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons. + +*NOTE:* This utility is not meant to be used standalone. Never run this utility directly. Always run [`afl-plot`](../../afl-plot), which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag). \ No newline at end of file -- cgit v1.2.3 From 533c612dc9cef84ee54c86493da8253373791b31 Mon Sep 17 00:00:00 2001 From: DMaroo Date: Fri, 6 Aug 2021 18:53:00 +0530 Subject: Updated README to contain description regarding plot_ui --- utils/README.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'utils') diff --git a/utils/README.md b/utils/README.md index b157424f..1c401237 100644 --- a/utils/README.md +++ b/utils/README.md @@ -5,6 +5,9 @@ Here's a quick overview of the stuff you can find in this directory: - afl_network_proxy - fuzz a target over the network: afl-fuzz on a host, target on an embedded system. + - plot_ui - simple UI window utility to display the + plots generated by afl-plot + - afl_proxy - skeleton file example to show how to fuzz something where you gather coverage data via different means, e.g. hw debugger -- cgit v1.2.3 From 73c7136bdb7e54789cbcb82afe8e17f81d1921e8 Mon Sep 17 00:00:00 2001 From: DMaroo Date: Sat, 7 Aug 2021 21:01:23 +0530 Subject: Start plot UI window maximized on launch --- utils/plot_ui/afl-plot-ui.c | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c index 856bf082..1a1eb0ed 100644 --- a/utils/plot_ui/afl-plot-ui.c +++ b/utils/plot_ui/afl-plot-ui.c @@ -141,6 +141,7 @@ int main(int argc, char **argv) { g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); + gtk_window_maximize(GTK_WINDOW(window)); gtk_main(); return EXIT_SUCCESS; -- cgit v1.2.3 From d832ed68eaa9bc514b788970c21a68e606c0dfea Mon Sep 17 00:00:00 2001 From: DMaroo Date: Sat, 7 Aug 2021 21:05:06 +0530 Subject: Updated README with build and install instructions --- utils/plot_ui/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'utils') diff --git a/utils/plot_ui/README.md b/utils/plot_ui/README.md index d8afa09f..145ec219 100644 --- a/utils/plot_ui/README.md +++ b/utils/plot_ui/README.md @@ -2,4 +2,14 @@ `afl-plot-ui` is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons. +Currently, this utility is not built by default. +You can manually build and install `afl-plot-ui` as follows + +```shell +sudo apt install libgtk-3-0 libgtk-3-dev pkg-config +make +cd ../../ +sudo make install +``` + *NOTE:* This utility is not meant to be used standalone. Never run this utility directly. Always run [`afl-plot`](../../afl-plot), which will, in turn, invoke this utility (when run using `-g` or `--graphical` flag). \ No newline at end of file -- cgit v1.2.3 From df74625df0324e17178dbf3c7c03484719ef6dd0 Mon Sep 17 00:00:00 2001 From: llzmb <46303940+llzmb@users.noreply.github.com> Date: Sun, 8 Aug 2021 01:29:32 +0200 Subject: Change afl to AFL in *.md (#1057) Changes in *.md files: - afl++ > AFL++ (acronym) - afl > AFL (compare https://github.com/google/AFL) Excluded from changes: - source code - function names - paths (folder and file names) - URLs --- utils/README.md | 4 ++-- utils/aflpp_driver/README.md | 2 +- utils/argv_fuzzing/README.md | 2 +- utils/defork/README.md | 2 +- utils/qbdi_mode/README.md | 2 +- utils/socket_fuzzing/README.md | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'utils') diff --git a/utils/README.md b/utils/README.md index 7fd6177a..b8df0b47 100644 --- a/utils/README.md +++ b/utils/README.md @@ -41,7 +41,7 @@ Here's a quick overview of the stuff you can find in this directory: - crash_triage - a very rudimentary example of how to annotate crashes with additional gdb metadata. - - custom_mutators - examples for the afl++ custom mutator interface in + - custom_mutators - examples for the AFL++ custom mutator interface in C and Python. Note: They were moved to ../custom_mutators/examples/ @@ -64,7 +64,7 @@ Here's a quick overview of the stuff you can find in this directory: - qemu_persistent_hook - persistent mode support module for qemu. - socket_fuzzing - a LD_PRELOAD library 'redirects' a socket to stdin - for fuzzing access with afl++ + for fuzzing access with AFL++ Note that the minimize_corpus.sh tool has graduated from the utils/ directory and is now available as ../afl-cmin. The LLVM mode has likewise diff --git a/utils/aflpp_driver/README.md b/utils/aflpp_driver/README.md index 4ca59776..30e2412f 100644 --- a/utils/aflpp_driver/README.md +++ b/utils/aflpp_driver/README.md @@ -1,4 +1,4 @@ -# afl++ drivers +# AFL++ drivers ## aflpp_driver diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md index fa8cad80..192d72f7 100644 --- a/utils/argv_fuzzing/README.md +++ b/utils/argv_fuzzing/README.md @@ -1,6 +1,6 @@ # argvfuzz -afl supports fuzzing file inputs or stdin. When source is available, +AFL supports fuzzing file inputs or stdin. When source is available, `argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin. `argvfuzz` tries to provide the same functionality for binaries. When loaded diff --git a/utils/defork/README.md b/utils/defork/README.md index 7e950323..657ef274 100644 --- a/utils/defork/README.md +++ b/utils/defork/README.md @@ -8,4 +8,4 @@ the target will belive it is running as the child, post-fork. This is defork.c from the amazing preeny project https://github.com/zardus/preeny -It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked. +It is altered for AFL++ to work with its fork-server: the initial fork will go through, the second fork will be blocked. diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index 334199f2..a68da616 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -1,7 +1,7 @@ # 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. +AFL++ versions first. Try frida_mode/ or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. ## 1) Introduction diff --git a/utils/socket_fuzzing/README.md b/utils/socket_fuzzing/README.md index 79f28bea..84398a71 100644 --- a/utils/socket_fuzzing/README.md +++ b/utils/socket_fuzzing/README.md @@ -8,4 +8,4 @@ a network socket. This is desock_dup.c from the amazing preeny project https://github.com/zardus/preeny -It is packaged in afl++ to have it at hand if needed +It is packaged in AFL++ to have it at hand if needed -- cgit v1.2.3 From a92952fa03e7aeed5f47c24e295dfbe49851bc98 Mon Sep 17 00:00:00 2001 From: DMaroo Date: Sun, 8 Aug 2021 14:52:25 +0530 Subject: Added resizable panes instead of static separators in afl-plot-ui The different plots can now be resized using dragging the panes. The resizing isn't completely smooth from the visual POV (I'm guessing this is because of embedding GNUplot), but once the position of the panels are set, the rest of the visual experience is as smooth as it was before. --- utils/plot_ui/afl-plot-ui.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'utils') diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c index 1a1eb0ed..9e96ad5b 100644 --- a/utils/plot_ui/afl-plot-ui.c +++ b/utils/plot_ui/afl-plot-ui.c @@ -32,7 +32,8 @@ int main(int argc, char **argv) { GtkWidget *cbuttons_frame; GtkWidget *cbuttons_hbox; - GtkWidget *separator_maj, *separator_min1, *separator_min2, *separator_min3; + GtkWidget *separator_top; + GtkWidget *pane1, *pane2, *pane3; GtkWidget *plots_vbox; GtkWidget *plot_edges_frame, *plot_exec_speed_frame, *plot_high_freq_frame, @@ -84,45 +85,53 @@ int main(int argc, char **argv) { gtk_container_add(GTK_CONTAINER(cbuttons_frame), cbuttons_hbox); gtk_box_pack_start(GTK_BOX(main_vbox), cbuttons_frame, FALSE, TRUE, 1); - separator_maj = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_start(GTK_BOX(main_vbox), separator_maj, FALSE, TRUE, 1); + separator_top = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + gtk_box_pack_start(GTK_BOX(main_vbox), separator_top, FALSE, TRUE, 1); plots_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); plot_edges_frame = gtk_frame_new("Edges"); - gtk_container_set_border_width(GTK_CONTAINER(plot_edges_frame), 5); + gtk_frame_set_shadow_type(GTK_FRAME(plot_edges_frame), GTK_SHADOW_IN); + gtk_container_set_border_width(GTK_CONTAINER(plot_edges_frame), 10); plot_edges = gtk_socket_new(); + gtk_widget_set_size_request(plot_edges, -1, 100); gtk_container_add(GTK_CONTAINER(plot_edges_frame), plot_edges); plot_exec_speed_frame = gtk_frame_new("Exec Speed"); - gtk_container_set_border_width(GTK_CONTAINER(plot_exec_speed_frame), 5); + gtk_frame_set_shadow_type(GTK_FRAME(plot_exec_speed_frame), GTK_SHADOW_IN); + gtk_container_set_border_width(GTK_CONTAINER(plot_exec_speed_frame), 10); plot_exec_speed = gtk_socket_new(); + gtk_widget_set_size_request(plot_exec_speed, -1, 100); gtk_container_add(GTK_CONTAINER(plot_exec_speed_frame), plot_exec_speed); plot_high_freq_frame = gtk_frame_new("High Frequency"); - gtk_container_set_border_width(GTK_CONTAINER(plot_high_freq_frame), 5); + gtk_frame_set_shadow_type(GTK_FRAME(plot_high_freq_frame), GTK_SHADOW_IN); + gtk_container_set_border_width(GTK_CONTAINER(plot_high_freq_frame), 10); plot_high_freq = gtk_socket_new(); + gtk_widget_set_size_request(plot_high_freq, -1, 100); gtk_container_add(GTK_CONTAINER(plot_high_freq_frame), plot_high_freq); plot_low_freq_frame = gtk_frame_new("Low Frequency"); - gtk_container_set_border_width(GTK_CONTAINER(plot_low_freq_frame), 5); + gtk_frame_set_shadow_type(GTK_FRAME(plot_low_freq_frame), GTK_SHADOW_IN); + gtk_container_set_border_width(GTK_CONTAINER(plot_low_freq_frame), 10); plot_low_freq = gtk_socket_new(); + gtk_widget_set_size_request(plot_low_freq, -1, 100); gtk_container_add(GTK_CONTAINER(plot_low_freq_frame), plot_low_freq); - separator_min1 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - separator_min2 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - separator_min3 = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + pane1 = gtk_paned_new(GTK_ORIENTATION_VERTICAL); + pane2 = gtk_paned_new(GTK_ORIENTATION_VERTICAL); + pane3 = gtk_paned_new(GTK_ORIENTATION_VERTICAL); - gtk_box_pack_start(GTK_BOX(plots_vbox), plot_edges_frame, TRUE, TRUE, 1); - gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min1, FALSE, TRUE, 1); + gtk_paned_pack1(GTK_PANED(pane1), plot_edges_frame, TRUE, FALSE); + gtk_paned_pack2(GTK_PANED(pane1), plot_exec_speed_frame, TRUE, FALSE); - gtk_box_pack_start(GTK_BOX(plots_vbox), plot_exec_speed_frame, TRUE, TRUE, 1); - gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min2, FALSE, TRUE, 1); + gtk_paned_pack1(GTK_PANED(pane2), pane1, TRUE, FALSE); + gtk_paned_pack2(GTK_PANED(pane2), plot_high_freq_frame, TRUE, FALSE); - gtk_box_pack_start(GTK_BOX(plots_vbox), plot_high_freq_frame, TRUE, TRUE, 1); - gtk_box_pack_start(GTK_BOX(plots_vbox), separator_min3, FALSE, TRUE, 1); + gtk_paned_pack1(GTK_PANED(pane3), pane2, TRUE, FALSE); + gtk_paned_pack2(GTK_PANED(pane3), plot_low_freq_frame, TRUE, FALSE); - gtk_box_pack_start(GTK_BOX(plots_vbox), plot_low_freq_frame, TRUE, TRUE, 1); + gtk_box_pack_start(GTK_BOX(plots_vbox), pane3, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(main_vbox), plots_vbox, TRUE, TRUE, 1); -- cgit v1.2.3 From 8f378ab00a809c0d85fc524a2d71e448c725bdbe Mon Sep 17 00:00:00 2001 From: DMaroo Date: Mon, 9 Aug 2021 11:14:57 +0530 Subject: Removed HEIGHT and WIDTH since the windows will anyways start maximized --- utils/plot_ui/afl-plot-ui.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'utils') diff --git a/utils/plot_ui/afl-plot-ui.c b/utils/plot_ui/afl-plot-ui.c index 9e96ad5b..2877f815 100644 --- a/utils/plot_ui/afl-plot-ui.c +++ b/utils/plot_ui/afl-plot-ui.c @@ -3,9 +3,6 @@ #include #include -#define WIDTH 400 -#define HEIGHT 640 - char USAGE[] = "is a helper utility for rendering the GNUplot graphs in a GTK window. This allows to real time resizing, scrolling, and cursor positioning features while viewing the graph. This utility also provides options to hide graphs using check buttons.\n \ \n \ @@ -43,7 +40,6 @@ int main(int argc, char **argv) { gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(window), WIDTH, HEIGHT); gtk_window_set_title(GTK_WINDOW(window), "Graph drawing"); gtk_container_set_border_width(GTK_CONTAINER(window), 10); -- cgit v1.2.3 From 23c240a94a0bd930e601e2dd575aa3608983b6ff Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 13:13:23 +0200 Subject: add newline at end --- utils/plot_ui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/plot_ui/Makefile b/utils/plot_ui/Makefile index 7ade8a40..b2013248 100644 --- a/utils/plot_ui/Makefile +++ b/utils/plot_ui/Makefile @@ -7,4 +7,4 @@ afl-plot-ui: afl-plot-ui.c $(CC) $(CFLAGS) -o afl-plot-ui afl-plot-ui.c $(LDFLAGS) clean: - rm -f afl-plot-ui \ No newline at end of file + rm -f afl-plot-ui -- cgit v1.2.3 From 87794121711f376fc1905e0451b744f9334e8075 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 20 Aug 2021 13:18:14 +0200 Subject: wording --- utils/qbdi_mode/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index a68da616..8b768906 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -1,8 +1,8 @@ # 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 frida_mode/ or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. +AFL++ versions. +Try frida_mode or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. ## 1) Introduction -- cgit v1.2.3