diff options
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | README.md | 56 | ||||
-rw-r--r-- | afl-dyninst.cpp | 24 | ||||
-rwxr-xr-x | afl-fuzz-dyninst.sh | 8 |
4 files changed, 52 insertions, 55 deletions
diff --git a/Makefile b/Makefile index 991299f..ca093f7 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,19 @@ # EDIT: path to dyninst binaries DYNINST_ROOT = /usr/local -# EDIT: you must set this to your dyninst build directory if you build with v10 -DYNINST_BUILD = /path/to/dyninst/build +# EDIT: you must set this to your dyninst build directory +DYNINST_BUILD = /path/to/dyninst/build-directory +#DYNINST_BUILD = /prg/tmp/dyninst/build-10.0.1 + +# EDIT: path to afl src if you do not set a symlink from ./afl to the afl directory +AFL_ROOT = ./afl # better dont touch these DYNINST9=-lcommon -liberty -lboost_system -DYNINST10=-I$(DYNINST_BUILD)/tbb/src/TBB/src/include -lboost_system -L$(DYNINST_BUILD)/tbb/lib -ltbb -Wl,-rpath $(DYNINST_BUILD)/tbb/lib +DYNINST10=-I$(DYNINST_BUILD)/tbb/src/TBB/src/include -lboost_system -ltbb # EDIT: set this to either DYNINST9 or DYNINST10 depending on what you installed -DYNINST_OPT = $(DYNINST9) - -# path to afl src -AFL_ROOT = ./afl +DYNINST_OPT = $(DYNINST10) # path to libelf and libdwarf DEPS_ROOT = /usr/local @@ -20,12 +21,12 @@ DEPS_ROOT = /usr/local # where to install INSTALL_ROOT = /usr/local -CXX = g++ +#CXX = g++ CXXFLAGS = -Wall -O3 -std=c++11 -g -O3 -std=c++11 LIBFLAGS = -fpic -shared CC = gcc -CFLAGS = -Wall -pedantic -g -std=gnu99 +CFLAGS = -Wall -O3 -g -std=gnu99 all: afl-dyninst libAflDyninst.so diff --git a/README.md b/README.md index eafa564..0757685 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ The tool has two parts. The instrumentation tool and the instrumentation library. Instrumentation library has an initialization callback and basic block callback functions which are designed to emulate what AFL is doing with afl-gcc/afl-g++/afl-as. + Instrumentation tool (afl-dyninst) instruments the supplied binary by inserting callbacks for each basic block and an initialization callback either at _init or at specified entry point. @@ -13,35 +14,33 @@ callback either at _init or at specified entry point. 0. Clone, compile and install dyninst: https://github.com/dyninst/dyninst/ -Note that you can also use dyninst 9.3.2, its actually less hassle, but has less platform support. And different bugs :) - -1. Edit the Makefile and set DYNINST_ROOT and AFL_ROOT to appropriate paths. +Note that you could also use dyninst 9.3.2, but has less platform support and +quite a few bugs. For using dyninst 9.x you have to edit the Makefile +Using at least 10.0.1 is highly recommended. -if you built dyninst 10.x or from directly from github: you also have to set DYNINST_BUILD to the .../dyninst/build directory and then set DYNINST_OPT to $(DYNINST10) -#### *NOTE* I recommend to stay at the github state at about July 2018 for the moment (eg. commit hash 6a71517fb076390ef2c00b4df1dbc5b0607bb5fe) -#### dyninst 10 is not stable currently! +1. Edit the Makefile and set DYNINST_ROOT and AFL_ROOT to appropriate paths. 2. make 3. make install 4. Download and install afl++ from https://github.com/vanhauser-thc/AFLplusplus -It's an up to date and enhanced version to the original afl with a better +It's an up to date and enhanced version to the original afl with better performance, new features and bugfixes. ### Building dyninst 10 building dyninst10 is a pain. I recommend the following steps: -1. remove elfutils if installed as distribution package +1. remove elfutils if installed as a distribution package 2. download the newest elfutils, make and (!) make install 3. install libboost-all-dev for your distribution 4. execute (depending where your libboost is installed, for me its /usr/lib/x86_64-linux-gnu): -``` +```shell cd /usr/lib/x86_64-linux-gnu && for i in libboost*.so libboost*.a; do n=`echo $i|sed 's/\./-mt./'` - ln -s $i $n + ln -s $i $n 2> /dev/null done ``` 5. git clone https://github.com/dyninst/dyninst ; mkdir build ; cd build ; cmake .. ; make ; make install @@ -63,11 +62,8 @@ Usage: ./afl-dyninst -dfvD -i INPUT_BINARY -o OUTPUT_BINARY -l INPUT_LIBRARY -e -S: do not instrument this function (repeat for more than one) -D: instrument fork server and forced exit functions but no basic blocks -x: experimental performance modes (can be set up to three times) - level 1: ~40-50%% improvement - level 2: ~100%% vs normal, ~40%% vs level 1 - level 3: ~110%% vs normal, ~5%% vs level 2 - level 3 replaces how basic block coverage works and can be tried if - normal mode or level 1 or 2 lead to crashes randomly. + -x (level 1) : ~40-50%% improvement + -xx (level 2): ~100%% vs normal, ~40%% vs level 1 -v: verbose output ``` @@ -116,14 +112,9 @@ basic block instrumentation. That would serve no purpose - unless there is another interesting tool coming up: afl-pin (already available at https://github.com/vanhauser-thc/afl-pin) and afl-dynamorio (wip) -Switch -x enables performance modes, -x level 1, -xx level 2 and -xxx level 3 -level 3 is only availble for intel x64 and can either save your ass or not -work for you whatsoever. +Switch -x enables performance modes, -x is level 1 and -xx is level 2. level 1 (-x) is highly recommended (+50%). level 2 (-xx) gives an additonal 40% but removes (usually unnecessary) precautions -level 3 (-xxx) gives only a very small additional speed and works differently, - it basically replaces the instrumented instructions by dyninst with own ones. - this is a good idea when you run into dyninst bugs. ## Example of running the tool @@ -132,28 +123,33 @@ Dyninst requires DYNINSTAPI_RT_LIB environment variable to point to the location of libdyninstAPI_RT.so. $ export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so -$ ./afl-dyninst -i ./rar -o ./rar_ins -e 0x4034c0 -s 100 +$ ./afl-dyninst -i ./unrar -o ./rar_ins -e 0x4034c0 -s 10 Skipping library: libAflDyninst.so Instrumenting module: DEFAULT_MODULE Inserting init callback. -Saving the instrumented binary to ./rar_ins... +Saving the instrumented binary to ./unrar_ins... All done! Happy fuzzing! Here we are instrumenting the rar binary with entrypoint at 0x4034c0 -(manualy found address of main), skipping the first 100 basic blocks -and outputing to rar_ins. +(manually found address of main), skipping the first 10 basic blocks +and outputing to unrar_ins + +You can also use the afl-dyninst.sh helper script which sets the required +environment variables for you. -## Running AFL on instrumented binary +## Running AFL on the instrumented binary NOTE: The instrumentation library "libDyninst.so" must be available in the current working directory or LD_LIBRARY_PATH as that is where the instrumented binary will be looking for it. -Since AFL checks if the binary has been instrumented by afl-gcc,AFL_SKIP_BIN_CHECK environment -variable needs to be set. No modifications to AFL it self is needed. +Since AFL checks if the binary has been instrumented by afl-gcc, the +AFL_SKIP_BIN_CHECK environment variable needs to be set. +No modifications to AFL itself is needed. $ export AFL_SKIP_BIN_CHECK=1 Then, AFL can be run as usual: $ afl-fuzz -i testcases/archives/common/gzip/ -o test_gzip -- ./gzip_ins -d -c -Note that there are the helper scripts afl-fuzz-dyninst.sh and afl-dyninst.sh for you which set the -required environment variables for you. +You can also use the afl-fuzz-dyninst.sh helper script which sets the required +environment variables for you. + diff --git a/afl-dyninst.cpp b/afl-dyninst.cpp index 5b25262..e5e7ff6 100644 --- a/afl-dyninst.cpp +++ b/afl-dyninst.cpp @@ -40,7 +40,7 @@ set < string > instrumentLibraries; set < string > runtimeLibraries; set < string > skipAddresses; set < unsigned long > exitAddresses; -unsigned int bbMinSize = 1; +unsigned int bbMinSize = 10; int bbSkip = 0, performance = 0; bool skipMainModule = false, do_bb = true, dynfix = false; unsigned long int insertions = 0; @@ -63,16 +63,13 @@ static const char *USAGE = "-dfvxD -i <binary> -o <binary> -l <library> -e <addr -e: entry point address to patch (required for stripped binaries)\n \ -E: exit point - force exit(0) at this address (repeat for more than one)\n \ -s: number of initial basic blocks to skip in binary\n \ - -m: minimum size of a basic bock to instrument (default: 1)\n \ + -m: minimum size of a basic bock to instrument (default: 10)\n \ -f: try to fix a dyninst bug that leads to crashes (loss of 20%% performance)\n \ -S: do not instrument this function (repeat for more than one)\n \ -D: instrument only a simple fork server and also forced exit functions\n \ - -x: experimental performance modes (can be set up to three times)\n \ - level 1: ~40-50%% improvement\n \ - level 2: ~100%% vs normal, ~40%% vs level 1\n \ - level 3: ~110%% vs normal, ~5%% vs level 2\n \ - level 3 replaces how basic block coverage works and can be tried if\n \ - normal mode or level 1 or 2 lead to crashes randomly.\n \ + -x: experimental performance modes (can be set up to two times)\n \ + -x (level 1): ~40-50%% improvement\n \ + -xx (level 2): ~100%% vs normal, ~40%% vs level 1\n \ -v: verbose output\n"; bool parseOptions(int argc, char **argv) { @@ -82,6 +79,7 @@ bool parseOptions(int argc, char **argv) { switch ((char) c) { case 'x': performance++; +/* if (performance == 3) { #if ( __amd64__ || __x86_64__ ) fprintf(stderr, "Warning: performance level 3 is currently totally experimental\n"); @@ -89,9 +87,9 @@ bool parseOptions(int argc, char **argv) { fprintf(stderr, "Warning: maximum performance level for non-intelx64 x86 is 2\n"); performance = 2; #endif - } else if (performance > 3) { - fprintf(stderr, "Warning: maximum performance level is 3\n"); - performance = 3; + } else*/ if (performance > 2) { + fprintf(stderr, "Warning: maximum performance level is 2\n"); + performance = 2; } break; case 'S': @@ -540,7 +538,9 @@ int main(int argc, char **argv) { (*moduleIter)->getName(moduleName, 1024); if ((*moduleIter)->isSharedLib()) { - if (instrumentLibraries.find(moduleName) == instrumentLibraries.end()) { + if (instrumentLibraries.find(moduleName) == instrumentLibraries.end() + && string(moduleName).find(".so") != string::npos + ) { cout << "Skipping library: " << moduleName << endl; continue; } diff --git a/afl-fuzz-dyninst.sh b/afl-fuzz-dyninst.sh index eceb678..710c558 100755 --- a/afl-fuzz-dyninst.sh +++ b/afl-fuzz-dyninst.sh @@ -1,12 +1,12 @@ #!/bin/bash test -z "$1" -o "$1" = "-h" && { echo Syntax: $0 afl-fuzz-options ; echo sets the afl-dyninst environment variables ; exit 1 ; } -sysctl -w kernel.core_pattern=core > /dev/null -sysctl -w kernel.randomize_va_space=0 > /dev/null -echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null +# +# remember to run afl-system-config ! +# export AFL_SKIP_BIN_CHECK=1 export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. -export AFL_EXIT_WHEN_DONE=1 +#export AFL_EXIT_WHEN_DONE=1 #export AFL_TMPDIR=/run/$$ #export AFL_PRELOAD=./desock.so:./libdislocator/libdislocator.so afl-fuzz $* |