persistent mode doc

This commit is contained in:
van Hauser
2020-02-08 15:41:17 +01:00
parent ce49ba428b
commit 079f177cda
4 changed files with 108 additions and 24 deletions

View File

@ -29,6 +29,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- CmpLog instrumentation for QEMU (-c afl-fuzz command line option) - CmpLog instrumentation for QEMU (-c afl-fuzz command line option)
- AFL_PERSISTENT_HOOK callback module for persistent QEMU - AFL_PERSISTENT_HOOK callback module for persistent QEMU
(see examples/qemu_persistent_hook) (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 - afl-cmin is now a sh script (invoking awk) instead of bash for portability
the original script is still present as afl-cmin.bash the original script is still present as afl-cmin.bash
- afl-showmap: -i dir option now allows processing multiple inputs using the - afl-showmap: -i dir option now allows processing multiple inputs using the

View File

@ -37,8 +37,12 @@ enum {
void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) { 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]); printf("reading into %p\n", regs[R_EDI]);
size_t r = read(0, g2h(regs[R_EDI]), 1024); size_t r = read(0, g2h(regs[R_EDI]), 1024);
regs[R_EAX] = r;
printf("readed %ld bytes\n", r); printf("readed %ld bytes\n", r);
} }

View File

@ -71,31 +71,11 @@ must be an address of a basic block.
## 4) Bonus feature #2: persistent mode ## 4) Bonus feature #2: persistent mode
QEMU mode supports also persistent mode for x86 and x86_64 targets. AFL++'s QEMU mode now supports also persistent mode for x86 and x86_64 targets.
The environment variable to enable it is AFL_QEMU_PERSISTENT_ADDR=`start addr`. This increases the speed by several factors, however it is a bit of work to set
In this variable you must specify the address of the function that up - but worth the effort.
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. Please see the extra documentation for it: [README.persistent.md](README.persistent.md)
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.
## 5) Bonus feature #3: CompareCoverage ## 5) Bonus feature #3: CompareCoverage

View File

@ -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