about summary refs log tree commit diff
path: root/unicorn_mode
diff options
context:
space:
mode:
Diffstat (limited to 'unicorn_mode')
-rw-r--r--unicorn_mode/README.md45
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
-rwxr-xr-xunicorn_mode/build_unicorn_support.sh2
-rw-r--r--unicorn_mode/samples/c/COMPILE.md3
-rw-r--r--unicorn_mode/samples/persistent/COMPILE.md12
-rw-r--r--unicorn_mode/samples/speedtest/README.md15
-rw-r--r--unicorn_mode/samples/speedtest/rust/Cargo.toml4
-rw-r--r--unicorn_mode/samples/speedtest/rust/src/main.rs47
m---------unicorn_mode/unicornafl0
-rwxr-xr-xunicorn_mode/update_uc_ref.sh4
10 files changed, 72 insertions, 62 deletions
diff --git a/unicorn_mode/README.md b/unicorn_mode/README.md
index d2b7d16f..ee4a7b22 100644
--- a/unicorn_mode/README.md
+++ b/unicorn_mode/README.md
@@ -8,10 +8,11 @@ The CompareCoverage and NeverZero counters features are by Andrea Fioraldi <andr
 
 ## 1) Introduction
 
-The code in ./unicorn_mode allows you to build the (Unicorn Engine)[https://github.com/unicorn-engine/unicorn] with AFL support.
+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 
+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-cc or used in QEMU mode.
 
 There is a significant performance penalty compared to native AFL,
@@ -25,7 +26,7 @@ For some pointers for more advanced emulation, take a look at [BaseSAFE](https:/
 ### Building AFL++'s Unicorn Mode
 
 First, make AFL++ as usual.
-Once that completes successfully you need to build and add in the Unicorn Mode 
+Once that completes successfully you need to build and add in the Unicorn Mode
 features:
 
 ```
@@ -33,10 +34,10 @@ cd unicorn_mode
 ./build_unicorn_support.sh
 ```
 
-NOTE: This script checks out a Unicorn Engine fork as submodule that has been tested 
-and is stable-ish, based on the unicorn engine `next` branch. 
+NOTE: This script checks out a Unicorn Engine fork as submodule that has been tested
+and is stable-ish, based on the unicorn engine `next` branch.
 
-Building Unicorn will take a little bit (~5-10 minutes). Once it completes 
+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
@@ -46,25 +47,24 @@ 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 the quality of starting 
+		+ Same ideas as any other AFL++ inputs
+		+ 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 in Rust, C, or Python, which:
 		+ Adds memory map regions
-		+ Loads binary code into memory		
+		+ Loads binary code into memory
 		+ Calls uc.afl_fuzz() / uc.afl_start_forkserver
 		+ Loads and verifies data to fuzz from a command-line specified file
-			+ AFL will provide mutated inputs by changing the file passed to 
+			+ AFL++ will provide mutated inputs by changing the file passed to
 			  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 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.
+			+ If input constraints (size, invalid bytes, etc.) are known they
+			  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 interesting code from beginning to end
-		+ If a crash is detected, the test harness must 'crash' by 
+		+ If a crash is detected, the test harness must 'crash' by
 		  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
@@ -77,14 +77,13 @@ afl-fuzz -U -m none -i /path/to/inputs -o /path/to/results -- ./test_harness @@
 The normal afl-fuzz command line format applies to everything here. Refer to
 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 uses slightly older concepts, but describes the general ideas, at:
+For a much clearer vision of what all of this looks like, refer to the sample
+provided in the 'unicorn_mode/samples' directory. There is also a blog 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'](./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.
 
@@ -105,8 +104,8 @@ Comparison instructions are currently instrumented only for the x86, x86_64 and
 
 ## 4) Gotchas, feedback, bugs
 
-Running the build script builds Unicornafl and its python bindings and installs 
-them on your system. 
+Running the build script builds Unicornafl and its python bindings and installs
+them on your system.
 This installation will leave any existing Unicorn installations untouched.
 If you want to use unicornafl instead of unicorn in a script,
 replace all `unicorn` imports with `unicornafl` inputs, everything else should "just work".
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index 0db54339..dbe3999f 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-c0e03d2c
+9df92d6868e8b219886e4b7458e5e134c48ff2c9
diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh
index 6c376f8d..f9c0be7f 100755
--- a/unicorn_mode/build_unicorn_support.sh
+++ b/unicorn_mode/build_unicorn_support.sh
@@ -20,7 +20,7 @@
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
 #
-#   http://www.apache.org/licenses/LICENSE-2.0
+#   https://www.apache.org/licenses/LICENSE-2.0
 #
 # This script downloads, patches, and builds a version of Unicorn with
 # minor tweaks to allow Unicorn-emulated binaries to be run under
diff --git a/unicorn_mode/samples/c/COMPILE.md b/unicorn_mode/samples/c/COMPILE.md
index 7da140f7..e5265071 100644
--- a/unicorn_mode/samples/c/COMPILE.md
+++ b/unicorn_mode/samples/c/COMPILE.md
@@ -6,6 +6,7 @@ This shows a simple harness for unicornafl in C
 
 The target can be built using the `make` command.
 Just make sure you have built unicorn support first:
+
 ```bash
 cd /path/to/afl/unicorn_mode
 ./build_unicorn_support.sh
@@ -19,4 +20,4 @@ was built in case you want to rebuild it or recompile it for any reason.
 
 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.
+Then load the binary and execute the main function directly.
diff --git a/unicorn_mode/samples/persistent/COMPILE.md b/unicorn_mode/samples/persistent/COMPILE.md
index 111dfc54..5e607aef 100644
--- a/unicorn_mode/samples/persistent/COMPILE.md
+++ b/unicorn_mode/samples/persistent/COMPILE.md
@@ -1,13 +1,16 @@
 # C Sample
 
 This shows a simple persistent harness for unicornafl in C.
-In contrast to the normal c harness, this harness manually resets the unicorn state on each new input.
-Thanks to this, we can rerun the testcase in unicorn multiple times, without the need to fork again.
+In contrast to the normal c harness, this harness manually resets the unicorn
+state on each new input.
+Thanks to this, you can rerun the test case in unicorn multiple times, without
+the need to fork again.
 
 ## Compiling sample.c
 
 The target can be built using the `make` command.
 Just make sure you have built unicorn support first:
+
 ```bash
 cd /path/to/afl/unicorn_mode
 ./build_unicorn_support.sh
@@ -19,6 +22,7 @@ You don't need to compile persistent_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 (persistent_target_x86_64.bin) was built using -g -O0 in gcc.
+The pre-built binary (persistent_target_x86_64.bin) was built using -g -O0 in
+gcc.
 
-We then load the binary and we execute the main function directly.
+Then load the binary and execute the main function directly.
\ No newline at end of file
diff --git a/unicorn_mode/samples/speedtest/README.md b/unicorn_mode/samples/speedtest/README.md
index 3c1184a2..bd5ba8d0 100644
--- a/unicorn_mode/samples/speedtest/README.md
+++ b/unicorn_mode/samples/speedtest/README.md
@@ -35,7 +35,6 @@ cd python
 
 TODO: add results here.
 
-
 ## Compiling speedtest_target.c
 
 You shouldn't need to compile simple_target.c since a X86_64 binary version is
@@ -44,22 +43,30 @@ 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.
 
-We then load the binary and execute the main function directly.
+Then load the binary and execute the main function directly.
+
+## Addresses for the harness
 
-## Addresses for the harness:
 To find the address (in hex) of main, run:
+
 ```bash
 objdump -M intel -D target | grep '<main>:' | cut -d" " -f1
 ```
+
 To find all call sites to magicfn, run:
+
 ```bash
 objdump -M intel -D target | grep '<magicfn>$' | cut -d":" -f1
 ```
+
 For malloc callsites:
+
 ```bash
 objdump -M intel -D target | grep '<malloc@plt>$' | cut -d":" -f1
 ```
+
 And free callsites:
+
 ```bash
 objdump -M intel -D target | grep '<free@plt>$' | cut -d":" -f1
-```
+```
\ No newline at end of file
diff --git a/unicorn_mode/samples/speedtest/rust/Cargo.toml b/unicorn_mode/samples/speedtest/rust/Cargo.toml
index c19ee0a1..9b81be0b 100644
--- a/unicorn_mode/samples/speedtest/rust/Cargo.toml
+++ b/unicorn_mode/samples/speedtest/rust/Cargo.toml
@@ -11,5 +11,5 @@ panic = "abort"
 
 [dependencies]
 unicornafl = { path = "../../../unicornafl/bindings/rust/", version="1.0.0" }
-capstone="0.6.0"
-libc="0.2.66"
\ No newline at end of file
+capstone="0.10.0"
+libc="0.2.66"
diff --git a/unicorn_mode/samples/speedtest/rust/src/main.rs b/unicorn_mode/samples/speedtest/rust/src/main.rs
index 105ba4b4..cded1a3c 100644
--- a/unicorn_mode/samples/speedtest/rust/src/main.rs
+++ b/unicorn_mode/samples/speedtest/rust/src/main.rs
@@ -11,12 +11,13 @@ use std::{
 };
 
 use unicornafl::{
+    afl::afl_fuzz,
     unicorn_const::{uc_error, Arch, Mode, Permission},
-    RegisterX86::{self, *},
-    Unicorn, UnicornHandle,
+    RegisterX86::*,
+    Unicorn,
 };
 
-const BINARY: &str = &"../target";
+const BINARY: &str = "../target";
 
 // Memory map for the code to be tested
 // Arbitrary address where code to test will be loaded
@@ -47,7 +48,7 @@ fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
 fn parse_locs(loc_name: &str) -> Result<Vec<u64>, io::Error> {
     let contents = &read_file(&format!("../target.offsets.{}", loc_name))?;
     //println!("Read: {:?}", contents);
-    Ok(str_from_u8_unchecked(&contents)
+    Ok(str_from_u8_unchecked(contents)
         .split('\n')
         .map(|x| {
             //println!("Trying to convert {}", &x[2..]);
@@ -87,8 +88,7 @@ fn main() {
 }
 
 fn fuzz(input_file: &str) -> Result<(), uc_error> {
-    let mut unicorn = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?;
-    let mut uc: UnicornHandle<'_, _> = unicorn.borrow();
+    let mut uc = Unicorn::new(Arch::X86, Mode::MODE_64)?;
 
     let binary =
         read_file(BINARY).unwrap_or_else(|_| panic!("Could not read modem image: {}", BINARY));
@@ -105,7 +105,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
     // Set the program counter to the start of the code
     let main_locs = parse_locs("main").unwrap();
     //println!("Entry Point: {:x}", main_locs[0]);
-    uc.reg_write(RegisterX86::RIP as i32, main_locs[0])?;
+    uc.reg_write(RIP, main_locs[0])?;
 
     // Setup the stack.
     uc.mem_map(
@@ -114,14 +114,14 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
         Permission::READ | Permission::WRITE,
     )?;
     // Setup the stack pointer, but allocate two pointers for the pointers to input.
-    uc.reg_write(RSP as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
+    uc.reg_write(RSP, STACK_ADDRESS + STACK_SIZE - 16)?;
 
     // Setup our input space, and push the pointer to it in the function params
     uc.mem_map(INPUT_ADDRESS, INPUT_MAX as usize, Permission::READ)?;
     // We have argc = 2
-    uc.reg_write(RDI as i32, 2)?;
+    uc.reg_write(RDI, 2)?;
     // RSI points to our little 2 QWORD space at the beginning of the stack...
-    uc.reg_write(RSI as i32, STACK_ADDRESS + STACK_SIZE - 16)?;
+    uc.reg_write(RSI, STACK_ADDRESS + STACK_SIZE - 16)?;
     // ... which points to the Input. Write the ptr to mem in little endian.
     uc.mem_write(
         STACK_ADDRESS + STACK_SIZE - 16,
@@ -133,13 +133,13 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
     let already_allocated_malloc = already_allocated.clone();
     // We use a very simple malloc/free stub here,
     // that only works for exactly one allocation at a time.
-    let hook_malloc = move |mut uc: UnicornHandle<'_, _>, addr: u64, size: u32| {
+    let hook_malloc = move |uc: &mut Unicorn<'_, _>, addr: u64, size: u32| {
         if already_allocated_malloc.get() {
             println!("Double malloc, not supported right now!");
             abort();
         }
         // read the first param
-        let malloc_size = uc.reg_read(RDI as i32).unwrap();
+        let malloc_size = uc.reg_read(RDI).unwrap();
         if malloc_size > HEAP_SIZE_MAX {
             println!(
                 "Tried to allocate {} bytes, but we may only allocate up to {}",
@@ -147,20 +147,20 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
             );
             abort();
         }
-        uc.reg_write(RAX as i32, HEAP_ADDRESS).unwrap();
-        uc.reg_write(RIP as i32, addr + size as u64).unwrap();
+        uc.reg_write(RAX, HEAP_ADDRESS).unwrap();
+        uc.reg_write(RIP, addr + size as u64).unwrap();
         already_allocated_malloc.set(true);
     };
 
     let already_allocated_free = already_allocated;
     // No real free, just set the "used"-flag to false.
-    let hook_free = move |mut uc: UnicornHandle<'_, _>, addr, size| {
+    let hook_free = move |uc: &mut Unicorn<'_, _>, addr, size| {
         if already_allocated_free.get() {
             println!("Double free detected. Real bug?");
             abort();
         }
         // read the first param
-        let free_ptr = uc.reg_read(RDI as i32).unwrap();
+        let free_ptr = uc.reg_read(RDI).unwrap();
         if free_ptr != HEAP_ADDRESS {
             println!(
                 "Tried to free wrong mem region {:x} at code loc {:x}",
@@ -168,7 +168,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
             );
             abort();
         }
-        uc.reg_write(RIP as i32, addr + size as u64).unwrap();
+        uc.reg_write(RIP, addr + size as u64).unwrap();
         already_allocated_free.set(false);
     };
 
@@ -177,8 +177,8 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
     */
 
     // This is a fancy print function that we're just going to skip for fuzzing.
-    let hook_magicfn = move |mut uc: UnicornHandle<'_, _>, addr, size| {
-        uc.reg_write(RIP as i32, addr + size as u64).unwrap();
+    let hook_magicfn = move |uc: &mut Unicorn<'_, _>, addr, size| {
+        uc.reg_write(RIP, addr + size as u64).unwrap();
     };
 
     for addr in parse_locs("malloc").unwrap() {
@@ -195,7 +195,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
     }
 
     let place_input_callback =
-        |uc: &mut UnicornHandle<'_, _>, afl_input: &mut [u8], _persistent_round| {
+        |uc: &mut Unicorn<'_, _>, afl_input: &mut [u8], _persistent_round| {
             // apply constraints to the mutated input
             if afl_input.len() > INPUT_MAX as usize {
                 //println!("Skipping testcase with leng {}", afl_input.len());
@@ -209,13 +209,12 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> {
 
     // return true if the last run should be counted as crash
     let crash_validation_callback =
-        |_uc: &mut UnicornHandle<'_, _>, result, _input: &[u8], _persistent_round| {
-            result != uc_error::OK
-        };
+        |_uc: &mut Unicorn<'_, _>, result, _input: &[u8], _persistent_round| result != uc_error::OK;
 
     let end_addrs = parse_locs("main_ends").unwrap();
 
-    let ret = uc.afl_fuzz(
+    let ret = afl_fuzz(
+        &mut uc,
         input_file,
         place_input_callback,
         &end_addrs,
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject 019b871539fe9ed3f41d882385a8b02c243d49a
+Subproject d4915053d477dd827b3fe4b494173d3fbf9f456
diff --git a/unicorn_mode/update_uc_ref.sh b/unicorn_mode/update_uc_ref.sh
index 7c1c7778..6e809a7b 100755
--- a/unicorn_mode/update_uc_ref.sh
+++ b/unicorn_mode/update_uc_ref.sh
@@ -21,10 +21,10 @@ fi
 
 git submodule init && git submodule update unicornafl || exit 1
 cd ./unicornafl || exit 1
-git fetch origin dev 1>/dev/null || exit 1
+git fetch origin uc1 1>/dev/null || exit 1
 git stash 1>/dev/null 2>/dev/null
 git stash drop 1>/dev/null 2>/dev/null
-git checkout dev
+git checkout uc1
 
 if [ -z "$NEW_VERSION" ]; then
   # No version provided, take HEAD.