diff options
l--------- | ChangeLog.md | 1 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | docs/Changelog.md (renamed from docs/ChangeLog.md) | 10 | ||||
-rw-r--r-- | examples/qemu_persistent_hook/read_into_rdi.c | 4 | ||||
-rw-r--r-- | libdislocator/libdislocator.so.c | 2 | ||||
-rw-r--r-- | qemu_mode/README.md | 30 | ||||
-rw-r--r-- | qemu_mode/README.persistent.md | 99 | ||||
-rwxr-xr-x | test/test.sh | 6 |
8 files changed, 123 insertions, 35 deletions
diff --git a/ChangeLog.md b/ChangeLog.md deleted file mode 120000 index 84ffa672..00000000 --- a/ChangeLog.md +++ /dev/null @@ -1 +0,0 @@ -docs/ChangeLog.md \ No newline at end of file diff --git a/Makefile b/Makefile index 70eac6b9..5af8444a 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,9 @@ endif ifneq "$(shell uname -m)" "x86_64" ifneq "$(shell uname -m)" "i386" ifneq "$(shell uname -m)" "amd64" + ifneq "$(shell uname -m)" "i86pc" AFL_NO_X86=1 + endif endif endif endif @@ -109,10 +111,12 @@ endif ifneq "$(findstring FreeBSD, $(shell uname))" "" CFLAGS += -pthread + LDFLAGS += -lpthread endif ifneq "$(findstring NetBSD, $(shell uname))" "" CFLAGS += -pthread + LDFLAGS += -lpthread endif ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" @@ -423,7 +427,7 @@ endif install -m 755 afl-as $${DESTDIR}$(HELPER_PATH) ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as - install -m 644 docs/*.md docs/ChangeLog $${DESTDIR}$(DOC_PATH) + install -m 644 docs/*.md $${DESTDIR}$(DOC_PATH) cp -r testcases/ $${DESTDIR}$(MISC_PATH) cp -r dictionaries/ $${DESTDIR}$(MISC_PATH) diff --git a/docs/ChangeLog.md b/docs/Changelog.md index ad0b9e88..f2c39e65 100644 --- a/docs/ChangeLog.md +++ b/docs/Changelog.md @@ -1,4 +1,4 @@ -# ChangeLog +# Changelog This is the list of all noteworthy changes made in every public release of the tool. See README for the general instruction manual. @@ -25,9 +25,11 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. instrumentation. compile normally and set AFL_LLVM_USE_TRACE_PC :) - LLVM 11 is supported - CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog) - - CmpLog instrumentation for QEMU - - AFL_PERSISTENT_HOOK callback module for persistent QEMU - (see examples/qemu_persistent_hook) + - qemu_mode: + - CmpLog instrumentation for QEMU (-c afl-fuzz command line option) + - AFL_PERSISTENT_HOOK callback module for persistent QEMU + (see examples/qemu_persistent_hook) + - added qemu_mode/README.persistent.md documentation - afl-cmin is now a sh script (invoking awk) instead of bash for portability the original script is still present as afl-cmin.bash - afl-showmap: -i dir option now allows processing multiple inputs using the diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c index fd4c9000..3994e790 100644 --- a/examples/qemu_persistent_hook/read_into_rdi.c +++ b/examples/qemu_persistent_hook/read_into_rdi.c @@ -37,8 +37,12 @@ enum { void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) { + // In this example the register RDI is pointing to the memory location + // of the target buffer, and the length of the input is in RAX. + printf("reading into %p\n", regs[R_EDI]); size_t r = read(0, g2h(regs[R_EDI]), 1024); + regs[R_EAX] = r; printf("readed %ld bytes\n", r); } diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c index a426c387..98f16358 100644 --- a/libdislocator/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -64,7 +64,7 @@ #include "config.h" #include "types.h" -#if __STDC_VERSION__ < 201112L +#if __STDC_VERSION__ < 201112L || defined __FreeBSD__ // use this hack if not C11 typedef struct { diff --git a/qemu_mode/README.md b/qemu_mode/README.md index ccfd50e3..95b75e9c 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -71,31 +71,11 @@ must be an address of a basic block. ## 4) Bonus feature #2: persistent mode -QEMU mode supports also persistent mode for x86 and x86_64 targets. -The environment variable to enable it is AFL_QEMU_PERSISTENT_ADDR=`start addr`. -In this variable you must specify the address of the function that -has to be the body of the persistent loop. -The code in this function must be stateless like in the LLVM persistent mode. -The return address on stack is patched like in WinAFL in order to repeat the -execution of such function. -Another modality to execute the persistent loop is to specify also the -AFL_QEMU_PERSISTENT_RET=`end addr` env variable. -With this variable assigned, instead of patching the return address, the -specified instruction is transformed to a jump towards `start addr`. -Note that the format of the addresses in such variables is hex. - -Note that the base address of PIE binaries in QEMU user mode is 0x4000000000. - -With the env variable AFL_QEMU_PERSISTENT_GPR you can tell QEMU to save the -original value of general purpose registers and restore them in each cycle. -This allows to use as persistent loop functions that make use of arguments on -x86_64. - -With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the -stack pointer in which QEMU can find the return address when `start addr` is -hitted. - -Use this mode with caution, probably it will not work at the first shot. +AFL++'s QEMU mode now supports also persistent mode for x86 and x86_64 targets. +This increases the speed by several factors, however it is a bit of work to set +up - but worth the effort. + +Please see the extra documentation for it: [README.persistent.md](README.persistent.md) ## 5) Bonus feature #3: CompareCoverage diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md new file mode 100644 index 00000000..6dba5a00 --- /dev/null +++ b/qemu_mode/README.persistent.md @@ -0,0 +1,99 @@ +# How to use the persistent mode in AFL++'s QEMU mode + +## 1) Introduction + +Persistent mode let you fuzz your target persistently between to +addresses - without forking for every fuzzing attempt. +This increases the speed by a factor between x2 and x5, hence it is +very, very valuable. + +The persistent mode is currently only available for x86/x86_64 targets. + + +## 2) How use the persistent mode + +### 2.1) The START address + +The start of the persistent mode has to be set with AFL_QEMU_PERSISTENT_ADDR. + +This address must be at the start of a function or the starting address of +basic block. This (as well as the RET address, see below) has to be defined +in hexadecimal with the 0x prefix. + +If the target is compiled with position independant code (PIE/PIC), you must +add 0x4000000000 to that address, because qemu loads to this base address. + +If this address is not valid, afl-fuzz will error during startup with the +message that the forkserver was not found. + + +### 2.2) the RET address + +The RET address is optional, and only needed if the the return should not be +at the end of the function to which the START address points into, but earlier. + +It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to +be set if the target is position independant. + + +### 2.3) the OFFSET + +If the START address is *not* the beginning of a function, and *no* RET has +been set (so the end of the loop will be at the end of the function), the +ESP pointer very likely has to be reset correctly. + +The value by which the ESP pointer has to be corrected has to set in the +variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET + +Now to get this value right here some help: +1. use gdb on the target +2. set a breakpoint to your START address +3. set a breakpoint to the end of the same function +4. "run" the target with a valid commandline +5. at the first breakpoint print the ESP value with +``` +print $esp +``` +6. "continue" the target until the second breakpoint +7. again print the ESP value +8. calculate the difference between the two values - and this is the offset + + +### 2.4) resetting the register state + +It is very, very likely you need to reste the register state when starting +a new loop. Because of this you 99% of the time should set + +AFL_QEMU_PERSISTENT_GPR=1 + + +## 3) optional parameters + +### 3.1) loop counter value + +The more stable your loop in the target, the longer you can run it, the more +unstable it is the lower the loop count should be. A low value would be 100, +the maximum value should be 10000. The default is 1000. +This value can be set with AFL_QEMU_PERSISTENT_CNT + +This is the same concept as in the llvm_mode persistent mode with __AFL_LOOP(). + + +### 3.2) a hook for in-memory fuzzing + +You can increase the speed of the persistent mode even more by bypassing all +the reading of the fuzzing input via a file by reading directly into the +memory address space of the target process. + +All this needs is that the START address has a register pointing to the +memory buffer, and another register holding the value of the read length +(or pointing to the memory where that value is held). + +If the target reads from an input file you have to supply an input file +that is of least of the size that your fuzzing input will be (and do not +supply @@). + +An example that you can use with little modification for your target can +be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook) +This shared library is specified via AFL_QEMU_PERSISTENT_HOOK + diff --git a/test/test.sh b/test/test.sh index 1709468e..db197cf2 100755 --- a/test/test.sh +++ b/test/test.sh @@ -75,7 +75,7 @@ $ECHO "${RESET}${GREY}[*] starting afl++ test framework ..." test -z "$SYS" && $ECHO "$YELLOW[-] uname -m did not succeed" $ECHO "$BLUE[*] Testing: ${AFL_GCC}, afl-showmap, afl-fuzz, afl-cmin and afl-tmin" -test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" && { +test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" && { test -e ../${AFL_GCC} -a -e ../afl-showmap -a -e ../afl-fuzz && { ../${AFL_GCC} -o test-instr.plain ../test-instr.c > /dev/null 2>&1 AFL_HARDEN=1 ../${AFL_GCC} -o test-compcov.harden test-compcov.c > /dev/null 2>&1 @@ -263,7 +263,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { $ECHO "$RED[!] afl-fuzz is not working correctly with llvm_mode" CODE=1 } - test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" || { + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" || { echo 000000000000000000000000 > in/in2 echo 111 > in/in3 mkdir -p in2 @@ -583,7 +583,7 @@ test -e ../afl-qemu-trace && { } rm -f errors - test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" && { + test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" && { $ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds" { export AFL_QEMU_PERSISTENT_ADDR=`expr 0x4$(nm test-instr | grep "T main" | awk '{print $1}' | sed 's/^.......//')` |