diff options
Diffstat (limited to 'qemu_mode/README.persistent.md')
-rw-r--r-- | qemu_mode/README.persistent.md | 141 |
1 files changed, 71 insertions, 70 deletions
diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index 2ca5c873..7210a8cc 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -2,118 +2,118 @@ ## 1) Introduction -Persistent mode lets 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. +Persistent mode lets 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. +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 env var AFL_QEMU_PERSISTENT_ADDR. +The start of the persistent loop has to be set with environment variable +`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, OFFSET or EXITS -(see below in 2.2, 2.3, 2.6) have to be set. -This address (as well as the RET address, see below) has to be defined in +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, OFFSET, or EXITS (see below in 2.2, 2.3, 2.6) 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 both RET and EXITS are 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). +function and will patch the return address (on stack or in the link register) to +return to START (like WinAFL). -*Note:* If the target is compiled with position independant code (PIE/PIC) -qemu loads these to a specific base address. -For 64 bit you have to add 0x4000000000 (9 zeroes) and for 32 bit 0x40000000 -(7 zeroes) to the 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 afl-qemu-trace TARGET-BINARY` +*Note:* If the target is compiled with position independent code (PIE/PIC) qemu +loads these to a specific base address. For 64 bit you have to add 0x4000000000 +(9 zeroes) and for 32 bit 0x40000000 (7 zeroes) to the 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 afl-qemu-trace +TARGET-BINARY`. 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 return should not be -at the end of the function to which the START address points into, but earlier. +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 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. +It is defined by setting `AFL_QEMU_PERSISTENT_RET`, and too 0x4000000000 has to +be set if the target is position independent. ### 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. +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 be set in the -variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET. +variable `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`. Now to get this value right here is 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 +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. +7. Print the ESP value with `print $esp` and take note of it. +8. "continue" the target until the second breakpoint. +9. Again print the ESP value. +10. 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 99% of the time you should set +``` AFL_QEMU_PERSISTENT_GPR=1 +``` -An example is when you want to use main() as persistent START: +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 stuff } ``` -If you don't save and restore the registers in x86_64, the parameter `argc` -will be lost at the second execution of the loop. +If you don't save and restore the registers in x86_64, the parameter `argc` will +be lost at the second execution of the loop. ### 2.5) Resetting the memory state This option restores the memory state using the AFL++ Snapshot LKM if loaded. Otherwise, all the writeable pages are restored. -To enable this option, set AFL_QEMU_PERSISTENT_MEM=1. +To enable this option, set `AFL_QEMU_PERSISTENT_MEM=1`. ### 2.6) Reset on exit() The user can force QEMU to set the program counter to START instead of executing the exit_group syscall and exit the program. -The env variable is AFL_QEMU_PERSISTENT_EXITS. +The environment variable is `AFL_QEMU_PERSISTENT_EXITS`. ### 2.7) Snapshot -AFL_QEMU_SNAPSHOT=address is just a "syntactical sugar" env variable that is equivalent to -the following set of variables: +`AFL_QEMU_SNAPSHOT=address` is just a "syntactical sugar" environment variable +that is equivalent to the following set of variables: ``` AFL_QEMU_PERSISTENT_ADDR=address @@ -127,26 +127,27 @@ AFL_QEMU_PERSISTENT_EXITS=1 ### 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 +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(). +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. +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 known location. You probably need -the value of the size of the buffer (maybe it is in a register when START is -hit). +memory buffer or that the memory buffer is at a known location. You probably +need the value of the size of the buffer (maybe it is in a register when START +is hit). -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 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: @@ -157,8 +158,8 @@ void afl_persistent_hook(struct ARCH_regs *regs, uint32_t input_buf_len); ``` -Where ARCH is one of x86, x86_64, arm or arm64. -You have to include `path/to/qemuafl/qemuafl/api.h`. +Where ARCH is one of x86, x86_64, arm or arm64. You have to include +`path/to/qemuafl/qemuafl/api.h`. In this hook, you can inspect and change the saved GPR state at START. @@ -168,8 +169,8 @@ with: `int afl_persistent_hook_init(void);` If this routine returns true, the shared mem fuzzing feature of AFL++ is used -and so the input_buf variables of the hook becomes meaningful. Otherwise, -you have to read the input from a file like stdin. +and so the input_buf variables of the hook becomes meaningful. Otherwise, you +have to read the input from a file like stdin. -An example that you can use with little modification for your target can -be found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook) +An example that you can use with little modification for your target can be +found here: [utils/qemu_persistent_hook](../utils/qemu_persistent_hook) \ No newline at end of file |