Justus Perlwitz 9951c38515 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`.
2025-06-05 10:00:45 +09:00

135 lines
4.2 KiB
Markdown

# QEMU persistent hook example
Compile the test binary and the library:
```
make
```
Fuzz with:
```
export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}')
export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so
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
...
```