about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--docs/Changelog.md1
-rw-r--r--examples/qemu_persistent_hook/read_into_rdi.c4
-rw-r--r--qemu_mode/README.md30
-rw-r--r--qemu_mode/README.persistent.md99
4 files changed, 109 insertions, 25 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 96cfa935..f2c39e65 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -29,6 +29,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
      - 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/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
+