mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-15 11:28:08 +00:00
Document QEMU persistent hook on mipsel
This adds a new persistent hook library `mipsel_read_into_a0.c`. With it, you can test the persistent hook on the *mipsel* architecture. I'm also updating the README in `utils/qemu_persistent_hook` and Makefile and explain how to test the persistent hook on *mipsel*. This all works thanks to qemuafl already having the correct CPU struct for *mipsel* in `qemuafl/api.h`. This patch also updates the root `.gitignore` file to ignore the two test binaries `test` and `mipsel_test`.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -108,6 +108,8 @@ utils/persistent_mode/persistent_demo
|
||||
utils/persistent_mode/persistent_demo_new
|
||||
utils/persistent_mode/persistent_demo_new_compat
|
||||
utils/persistent_mode/test-instr
|
||||
utils/qemu_persistent_hook/mipsel_test
|
||||
utils/qemu_persistent_hook/test
|
||||
utils/replay_record/persistent_demo_replay
|
||||
utils/replay_record/persistent_demo_replay_compat
|
||||
utils/replay_record/persistent_demo_replay_argparse
|
||||
|
@ -2,5 +2,9 @@ all:
|
||||
$(CC) -no-pie test.c -o test
|
||||
$(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so
|
||||
|
||||
all_mipsel: test.c mipsel_read_into_a0.c
|
||||
$(CPU_TARGET_CC) -no-pie test.c -o mipsel_test
|
||||
$(CC) -fPIC -shared mipsel_read_into_a0.c -o mipsel_read_into_a0.so
|
||||
|
||||
clean:
|
||||
rm -rf in out test read_into_rdi.so
|
||||
rm -rf in out test read_into_rdi.so mipsel_test mipsel_read_into_a0.so
|
||||
|
@ -16,4 +16,119 @@ mkdir in
|
||||
echo 0000 > in/in
|
||||
|
||||
../../afl-fuzz -Q -i in -o out -- ./test
|
||||
```
|
||||
```
|
||||
|
||||
## Example for mipsel architecture
|
||||
|
||||
Compile QEMU with `mipsel` support by running the following:
|
||||
|
||||
```bash
|
||||
# From root directory
|
||||
cd qemu_mode && CPU_TARGET=mipsel ./build_qemu_support.sh
|
||||
```
|
||||
|
||||
To compile binaries for `mipsel`, you need a GCC cross-compiler for
|
||||
the target architecture.
|
||||
How to build a GCC cross-compiler is out of scope for this document, but you
|
||||
may find this
|
||||
[OSDev Wiki Tutorial](https://wiki.osdev.org/GCC_Cross-Compiler) helpful.
|
||||
If you are using Nix, you may find
|
||||
[this tutorial](https://ayats.org/blog/nix-cross) useful.
|
||||
|
||||
The next step assumes that you have a GCC cross-compiler for `mipsel` available
|
||||
under `mipsel-gnu-linux-cc`. Verify that `qemu_mode` works properly by running
|
||||
`test/test-qemu-mode.sh`:
|
||||
|
||||
```bash
|
||||
# From root directory
|
||||
cd test
|
||||
CPU_TARGET_CC=mipsel-linux-gnu-cc CPU_TARGET=mipsel ./test-qemu-mode.sh
|
||||
```
|
||||
|
||||
The output should look something like this:
|
||||
|
||||
```
|
||||
[*] Using environment variable CPU_TARGET=mipsel for SYS
|
||||
[*] starting AFL++ test framework ...
|
||||
[*] Testing: qemu_mode
|
||||
[*] Using mipsel-linux-gnu-cc as compiler for target
|
||||
[*] running afl-fuzz for qemu_mode, this will take approx 10 seconds
|
||||
[+] afl-fuzz is working correctly with qemu_mode
|
||||
[*] running afl-fuzz for qemu_mode AFL_ENTRYPOINT, this will take approx 6 seconds
|
||||
[+] afl-fuzz is working correctly with qemu_mode AFL_ENTRYPOINT
|
||||
[-] not an intel or arm platform, cannot test qemu_mode compcov
|
||||
[-] not an intel or arm platform, cannot test qemu_mode cmplog
|
||||
[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds
|
||||
[+] afl-fuzz is working correctly with persistent qemu_mode
|
||||
[+] persistent qemu_mode was noticeable faster than standard qemu_mode
|
||||
[*] running afl-fuzz for persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS, this will take approx 10 seconds
|
||||
[+] afl-fuzz is working correctly with persistent qemu_mode and AFL_QEMU_PERSISTENT_EXITS
|
||||
[+] persistent qemu_mode with AFL_QEMU_PERSISTENT_EXITS was noticeable faster than standard qemu_mode
|
||||
[-] we cannot test qemu_mode unsigaction library (32 bit) because it is not present
|
||||
[+] qemu_mode unsigaction library (64 bit) ignores signals
|
||||
[*] 1 test cases completed.
|
||||
[-] not all test cases were executed
|
||||
[+] all tests were successful :-)
|
||||
```
|
||||
|
||||
Then, compile the test binary and library for `mipsel` using the following
|
||||
`make` command:
|
||||
|
||||
```bash
|
||||
CPU_TARGET_CC=mipsel-linux-gnu-cc make all_mipsel
|
||||
```
|
||||
|
||||
Make sure that the test binary and library have the correct format. When you
|
||||
run `file` on the two output files, you should see something like the
|
||||
following:
|
||||
|
||||
```
|
||||
$ file mipsel_read_into_a0.so mipsel_test
|
||||
mipsel_read_into_a0.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, not stripped
|
||||
mipsel_test: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /nix/store/837z8p51k37n0s1l3hlawx6inc60cq9d-uclibc-ng-mipsel-linux-gnu-1.0.50/lib/ld64-uClibc.so.1, not stripped
|
||||
```
|
||||
|
||||
Then, like in the previous section, prepare the fuzzing environment:
|
||||
|
||||
```bash
|
||||
export AFL_QEMU_PERSISTENT_ADDR=0x$(nm mipsel_test | grep "T target_func" | awk '{print $1}')
|
||||
export AFL_QEMU_PERSISTENT_HOOK=./mipsel_read_into_a0.so
|
||||
|
||||
mkdir in
|
||||
echo 0000 > in/in
|
||||
|
||||
# Set the following environment variables to avoid having to adjust
|
||||
# kernel settings:
|
||||
export AFL_SKIP_CPUFREQ=1
|
||||
export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
```
|
||||
|
||||
Run the fuzzer using the following command:
|
||||
|
||||
```bash
|
||||
../../afl-fuzz -V10 -Q -i in -o out -- ./mipsel_test
|
||||
```
|
||||
|
||||
If you run the fuzzer with `export AFL_DEBUG=1`, you should see the following
|
||||
repeating output:
|
||||
|
||||
```
|
||||
...
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:1
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:1
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:185
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:5
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:113
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:28
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:78
|
||||
Placing input into 0x410950
|
||||
buffer:0x410950, size:2
|
||||
...
|
||||
```
|
||||
|
35
utils/qemu_persistent_hook/mipsel_read_into_a0.c
Normal file
35
utils/qemu_persistent_hook/mipsel_read_into_a0.c
Normal file
@ -0,0 +1,35 @@
|
||||
#define TARGET_MIPS
|
||||
#include "../../qemu_mode/qemuafl/qemuafl/api.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
|
||||
#define h2g(x) ((uint64_t)(x) - guest_base)
|
||||
|
||||
void afl_persistent_hook(struct mips_regs *regs, uint64_t guest_base,
|
||||
uint8_t *input_buf, uint32_t input_buf_len) {
|
||||
|
||||
// In this example the register $a0 is pointing to the memory location
|
||||
// of the target buffer, and the length of the input is in $a1.
|
||||
// This can be seen with a debugger, e.g. gdb (and "disass main")
|
||||
|
||||
printf("Placing input into 0x%lx\n", regs->a0);
|
||||
|
||||
if (input_buf_len > 1024) input_buf_len = 1024;
|
||||
memcpy(g2h(regs->a0), input_buf, input_buf_len);
|
||||
regs->a1 = input_buf_len;
|
||||
|
||||
}
|
||||
|
||||
#undef g2h
|
||||
#undef h2g
|
||||
|
||||
int afl_persistent_hook_init(void) {
|
||||
|
||||
// 1 for shared memory input (faster), 0 for normal input (you have to use
|
||||
// read(), input_buf will be NULL)
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user