about summary refs log tree commit diff
path: root/qemu_mode/README.persistent.md
diff options
context:
space:
mode:
Diffstat (limited to 'qemu_mode/README.persistent.md')
-rw-r--r--qemu_mode/README.persistent.md131
1 files changed, 131 insertions, 0 deletions
diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md
new file mode 100644
index 00000000..c96a451b
--- /dev/null
+++ b/qemu_mode/README.persistent.md
@@ -0,0 +1,131 @@
+# How to use the persistent mode in AFL++'s QEMU mode
+
+## 1) Introduction
+
+Persistent mode let you fuzz your target persistently between two
+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, arm
+and aarch64 targets.
+
+## 2) How use the persistent mode
+
+### 2.1) The START address
+
+The start of the persistent loop has to be set with AFL_QEMU_PERSISTENT_ADDR.
+
+This address can be the address of whatever instruction.
+Setting this address to the start of a function makes the usage simple.
+If the address is however within a function, either RET or OFFSET (see below
+in 2.2 and 2.3) have to be set.
+This address (as well as the RET address, see below) has to be defined in
+hexadecimal with the 0x prefix or as a decimal value.
+
+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.
+On strange setups the base address set by QEMU for PIE executable may change,
+you can check it printing the process map using AFL_QEMU_DEBUG_MAPS=1.
+
+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 the last instruction of the persistent loop.
+The emulator will emit a jump to START when translating the instruction at RET.
+It 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.
+
+If it is not set, QEMU will assume that START points to a function and will
+patch the return address (on stack or in the link register) to return to START
+(like WinAFL).
+
+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
+
+This option is valid only for x86/x86_64 only, arm/aarch64 do not save the
+return address on stack.
+
+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 but START
+will not be at the beginning of it), we need an offset from the ESP pointer
+to locate the return address to patch.
+
+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 "main" (this is required for PIE/PIC binaries so the
+   addresses are set up)
+3. "run" the target with a valid commandline
+4. set a breakpoint to the function in which START is contained
+5. set a breakpoint to your START address
+6. "continue" to the function start breakpoint
+6. print the ESP value with `print $esp` and take note of it
+7. "continue" the target until the second breakpoint
+8. again print the ESP value
+9. 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 restore the general purpose registers state
+when starting a new loop. Because of this you 99% of the time should set
+
+AFL_QEMU_PERSISTENT_GPR=1
+
+An example, is when you want to use main() as persistent START:
+
+```c
+int main(int argc, char **argv) {
+
+  if (argc < 2) return 1;
+  
+  // do stuffs
+
+}
+```
+
+If you don't save and restore the registers in x86_64, the paramteter argc
+will be lost at the second execution of the loop.
+
+## 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 that can reach the
+memory buffer or that the memory buffer is at a know location. You probably need
+the value of the size of the buffer (maybe it is in a register when START is
+hitted).
+
+The persistent hook will execute a function on every persistent iteration
+(at the start START) defined in a shared object specified with
+AFL_QEMU_PERSISTENT_HOOK=/path/to/hook.so.
+
+The signature is:
+
+```c
+void afl_persistent_hook(uint64_t* regs, uint64_t guest_base);
+```
+
+In this hook, you can inspect and change the saved GPR state at START.
+
+An example that you can use with little modification for your target can
+be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook)