about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDominik Maier <domenukk@gmail.com>2021-02-27 17:19:00 +0100
committerDominik Maier <domenukk@gmail.com>2021-02-27 17:19:00 +0100
commit2ad495ad0a9e4721cf20354af4c4f7222d6c239e (patch)
treef0a25fb983bd7d56197078d89d58791b61dd1b63
parent8e051fd075e2854930bf828c5d23fe6dc648e1ed (diff)
downloadafl++-2ad495ad0a9e4721cf20354af4c4f7222d6c239e.tar.gz
reworked unicornafl documentation
-rw-r--r--unicorn_mode/README.md55
-rw-r--r--unicorn_mode/samples/c/COMPILE.md2
2 files changed, 36 insertions, 21 deletions
diff --git a/unicorn_mode/README.md b/unicorn_mode/README.md
index f6bd4d12..b3df44fa 100644
--- a/unicorn_mode/README.md
+++ b/unicorn_mode/README.md
@@ -8,19 +8,19 @@ The CompareCoverage and NeverZero counters features are by Andrea Fioraldi <andr
 
 ## 1) Introduction
 
-The code in ./unicorn_mode allows you to build a standalone feature that
-leverages the Unicorn Engine and allows callers to obtain instrumentation 
+The code in ./unicorn_mode allows you to build the (Unicorn Engine)[https://github.com/unicorn-engine/unicorn] with afl support.
+This means, you can run anything that can be emulated in unicorn and obtain instrumentation
 output for black-box, closed-source binary code snippets. This mechanism 
 can be then used by afl-fuzz to stress-test targets that couldn't be built 
-with afl-gcc or used in QEMU mode, or with other extensions such as 
-TriforceAFL.
+with afl-cc or used in QEMU mode.
 
 There is a significant performance penalty compared to native AFL,
 but at least we're able to use AFL++ on these binaries, right?
 
 ## 2) How to use
 
-Requirements: you need an installed python environment.
+First, you will need a working harness for your target in unicorn, using Python, C, or Rust.
+For some pointers for more advanced emulation, take a look at [BaseSAFE](https://github.com/fgsect/BaseSAFE) and [Qiling](https://github.com/qilingframework/qiling).
 
 ### Building AFL++'s Unicorn Mode
 
@@ -34,23 +34,23 @@ cd unicorn_mode
 ```
 
 NOTE: This script checks out a Unicorn Engine fork as submodule that has been tested 
-and is stable-ish, based on the unicorn engine master. 
+and is stable-ish, based on the unicorn engine `next` branch. 
 
 Building Unicorn will take a little bit (~5-10 minutes). Once it completes 
 it automatically compiles a sample application and verifies that it works.
 
 ### Fuzzing with Unicorn Mode
 
-To really use unicorn-mode effectively you need to prepare the following:
+To use unicorn-mode effectively you need to prepare the following:
 
 	* Relevant binary code to be fuzzed
 	* Knowledge of the memory map and good starting state
 	* Folder containing sample inputs to start fuzzing with
 		+ Same ideas as any other AFL inputs
-		+ Quality/speed of results will depend greatly on quality of starting 
+		+ Quality/speed of results will depend greatly on the quality of starting 
 		  samples
 		+ See AFL's guidance on how to create a sample corpus
-	* Unicornafl-based test harness which:
+	* Unicornafl-based test harness in Rust, C, or Python, which:
 		+ Adds memory map regions
 		+ Loads binary code into memory		
 		+ Calls uc.afl_fuzz() / uc.afl_start_forkserver
@@ -59,13 +59,13 @@ To really use unicorn-mode effectively you need to prepare the following:
 			  the test harness
 			+ Presumably the data to be fuzzed is at a fixed buffer address
 			+ If input constraints (size, invalid bytes, etc.) are known they 
-			  should be checked after the file is loaded. If a constraint 
-			  fails, just exit the test harness. AFL will treat the input as 
+			  should be checked in the place_input handler. If a constraint 
+			  fails, just return false from the handler. AFL will treat the input as 
 			  'uninteresting' and move on.
 		+ Sets up registers and memory state for beginning of test
-		+ Emulates the interested code from beginning to end
+		+ Emulates the interesting code from beginning to end
 		+ If a crash is detected, the test harness must 'crash' by 
-		  throwing a signal (SIGSEGV, SIGKILL, SIGABORT, etc.)
+		  throwing a signal (SIGSEGV, SIGKILL, SIGABORT, etc.), or indicate a crash in the crash validation callback.
 
 Once you have all those things ready to go you just need to run afl-fuzz in
 'unicorn-mode' by passing in the '-U' flag:
@@ -79,11 +79,12 @@ AFL's main documentation for more info about how to use afl-fuzz effectively.
 
 For a much clearer vision of what all of this looks like, please refer to the
 sample provided in the 'unicorn_mode/samples' directory. There is also a blog
-post that goes over the basics at:
+post that uses slightly older concepts, but describes the general ideas, at:
 
 [https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf](https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf)
 
-The 'helper_scripts' directory also contains several helper scripts that allow you 
+
+The ['helper_scripts'](./helper_scripts) directory also contains several helper scripts that allow you 
 to dump context from a running process, load it, and hook heap allocations. For details
 on how to use this check out the follow-up blog post to the one linked above.
 
@@ -92,10 +93,10 @@ A example use of AFL-Unicorn mode is discussed in the paper Unicorefuzz:
 
 ## 3) Options
 
-As for the QEMU-based instrumentation, the afl-unicorn twist of afl++
-comes with a sub-instruction based instrumentation similar in purpose to laf-intel.
+As for the QEMU-based instrumentation, unicornafl comes with a sub-instruction based instrumentation similar in purpose to laf-intel.
 
 The options that enable Unicorn CompareCoverage are the same used for QEMU.
+This will split up each multi-byte compare to give feedback for each correct byte.
 AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate values.
 
 AFL_COMPCOV_LEVEL=2 instruments all comparison instructions.
@@ -119,6 +120,20 @@ unicornafl.monkeypatch()
 
 This will replace all unicorn imports with unicornafl inputs.
 
-Refer to the [samples/arm_example/arm_tester.c](samples/arm_example/arm_tester.c) for an example
-of how to do this properly! If you don't get this right, AFL will not 
-load any mutated inputs and your fuzzing will be useless!
+5) Examples
+
+Apart from reading the documentation in `afl.c` and the python bindings of unicornafl, the best documentation are the [samples/](./samples).
+The following examples exist at the time of writing:
+
+- c: A simple example how to use the c bindings
+- compcov_x64: A python example that uses compcov to traverse hard-to-reach blocks
+- persistent: A c example using persistent mode for maximum speed, and resetting the target state between each iteration
+- simple: A simple python example
+- speedtest/c: The c harness for an example target, used to compare c, python, and rust bindings and fix speed issues
+- speedtest/python: Fuzzing the same target in python
+- speedtest/rust: Fuzzing the same target using a rust harness
+
+Usually, the place to look at is the `harness` in each folder. The source code in each harness is pretty well documented.
+Most harnesses also have the `afl-fuzz` commandline, or even offer a `make fuzz` Makefile target.
+Targets in these folders, if x86, can usually be made using `make target` in each folder or get shipped pre-built (plus their source).
+Especially take a look at the [speedtest documentation](./samples/speedtest/README.md) to see how the languages compare.
\ No newline at end of file
diff --git a/unicorn_mode/samples/c/COMPILE.md b/unicorn_mode/samples/c/COMPILE.md
index 7857e5bf..7da140f7 100644
--- a/unicorn_mode/samples/c/COMPILE.md
+++ b/unicorn_mode/samples/c/COMPILE.md
@@ -17,6 +17,6 @@ You shouldn't need to compile simple_target.c since a X86_64 binary version is
 pre-built and shipped in this sample folder. This file documents how the binary
 was built in case you want to rebuild it or recompile it for any reason.
 
-The pre-built binary (simple_target_x86_64.bin) was built using -g -O0 in gcc.
+The pre-built binary (persistent_target_x86_64) was built using -g -O0 in gcc.
 
 We then load the binary and execute the main function directly.