about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/afl-fuzz-init.c6
-rw-r--r--unicorn_mode/samples/c/a.outbin17184 -> 0 bytes
-rw-r--r--unicorn_mode/samples/c/harness.c81
-rw-r--r--unicorn_mode/samples/c/persistent_target.c39
-rw-r--r--unicorn_mode/samples/c/persistent_target_x86_64bin0 -> 16544 bytes
-rw-r--r--unicorn_mode/samples/persistent/.gitignore3
-rw-r--r--unicorn_mode/samples/persistent/COMPILE.md24
-rw-r--r--unicorn_mode/samples/persistent/Makefile42
-rw-r--r--unicorn_mode/samples/persistent/harness.c269
-rw-r--r--unicorn_mode/samples/persistent/persistent_target.c39
-rw-r--r--unicorn_mode/samples/persistent/persistent_target_x86_64bin0 -> 16544 bytes
-rw-r--r--unicorn_mode/samples/persistent/sample_all.sh18
-rw-r--r--unicorn_mode/samples/persistent/sample_inputs/sample1.bin1
-rw-r--r--unicorn_mode/samples/persistent/sample_inputs/sample2.binbin0 -> 1 bytes
-rw-r--r--unicorn_mode/samples/persistent/sample_inputs/sample3.bin1
-rw-r--r--unicorn_mode/samples/persistent/sample_inputs/sample4.bin1
-rw-r--r--unicorn_mode/samples/persistent/sample_inputs/sample5.bin1
-rw-r--r--unicorn_mode/samples/persistent/simple_target_noncrashing.c (renamed from unicorn_mode/samples/c/simple_target.c)7
-rw-r--r--unicorn_mode/samples/persistent/simple_target_x86_64bin0 -> 17624 bytes
19 files changed, 502 insertions, 30 deletions
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 219be822..2ef2c4e7 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1940,17 +1940,17 @@ void check_binary(u8* fname) {
 
   }
 
-  if ((qemu_mode || unicorn_mode) &&
+  if ((qemu_mode) &&
       memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
          "This program appears to be instrumented with afl-gcc, but is being "
          "run in\n"
-         "    QEMU or Unicorn mode (-Q or -U). This is probably not what you "
+         "    QEMU mode (-Q). This is probably not what you "
          "want -\n"
          "    this setup will be slow and offer no practical benefits.\n");
 
-    FATAL("Instrumentation found in -Q or -U mode");
+    FATAL("Instrumentation found in -Q mode");
 
   }
 
diff --git a/unicorn_mode/samples/c/a.out b/unicorn_mode/samples/c/a.out
deleted file mode 100644
index 176c25e1..00000000
--- a/unicorn_mode/samples/c/a.out
+++ /dev/null
Binary files differdiff --git a/unicorn_mode/samples/c/harness.c b/unicorn_mode/samples/c/harness.c
index a987b8e1..31416ae2 100644
--- a/unicorn_mode/samples/c/harness.c
+++ b/unicorn_mode/samples/c/harness.c
@@ -28,35 +28,56 @@
 #include <unicorn/unicorn.h>
 
 // Path to the file containing the binary to emulate
-#define BINARY_FILE ("simple_target_x86_64")
+#define BINARY_FILE ("persistent_target_x86_64")
 
 // Memory map for the code to be tested
 // Arbitrary address where code to test will be loaded
-#define BASE_ADDRESS (0x100000)
-#define CODE_ADDRESS (0x101119)
-#define END_ADDRESS  (0x1011d7)
+static const int64_t BASE_ADDRESS = 0x100000;
+static const int64_t CODE_ADDRESS = 0x101139;
+static const int64_t END_ADDRESS = 0x10120d;
 // Address of the stack (Some random address again)
-#define STACK_ADDRESS (((int64_t) 0x01) << 58)
+static const int64_t STACK_ADDRESS = (((int64_t) 0x01) << 58);
 // Size of the stack (arbitrarily chosen, just make it big enough)
-#define STACK_SIZE (0x10000)  
+static const int64_t STACK_SIZE = 0x10000;
 // Location where the input will be placed (make sure the emulated program knows this somehow, too ;) )
-#define INPUT_LOCATION (0x10000)
+static const int64_t INPUT_LOCATION = 0x10000;
 // Inside the location, we have an ofset in our special case
-#define INPUT_OFFSET (0x16) 
+static const int64_t INPUT_OFFSET = 0x16;
 // Maximum allowable size of mutated data from AFL
-#define INPUT_SIZE_MAX (0x10000)  
+static const int64_t INPUT_SIZE_MAX = 0x10000;
 // Alignment for unicorn mappings (seems to be needed)
-#define ALIGNMENT ((uint64_t) 0x1000)
+static const int64_t ALIGNMENT = 0x1000;
+
+// In our special case, we emulate main(), so argc is needed.
+static const uint64_t EMULATED_ARGC = 2;
+
+// The return from our fake strlen
+static size_t current_input_len = 0;
 
 static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
     printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
 }
 
-static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
-{
+static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
     printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
 }
 
+/*
+The sample uses strlen, since we don't have a loader or libc, we'll fake it.
+We know the strlen will return the lenght of argv[1] that we just planted.
+It will be a lot faster than an actual strlen for this specific purpose.
+*/
+static void hook_strlen(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
+    //Hook
+    //116b:       e8 c0 fe ff ff          call   1030 <strlen@plt>
+    // We place the return at RAX
+    //printf("Strlen hook at addr 0x%lx (size: 0x%x), result: %ld\n", address, size, current_input_len);
+    uc_reg_write(uc, UC_X86_REG_RAX, &current_input_len);
+    // We skip the actual call by updating RIP
+    uint64_t next_addr = address + size; 
+    uc_reg_write(uc, UC_X86_REG_RIP, &next_addr);
+}
+
 /* Unicorn page needs to be 0x1000 aligned, apparently */
 static uint64_t pad(uint64_t size) {
     if (size % ALIGNMENT == 0) return size;
@@ -99,11 +120,25 @@ static bool place_input_callback(
     void *data
 ){
     // printf("Placing input with len %ld to %x\n", input_len, DATA_ADDRESS);
-    if (input_len >= INPUT_SIZE_MAX - INPUT_OFFSET) {
-        // Test input too long, ignore this testcase
+    if (input_len < 1 || input_len >= INPUT_SIZE_MAX - INPUT_OFFSET) {
+        // Test input too short or too long, ignore this testcase
         return false;
     }
+
+    // For persistent mode, we have to set up stack and memory each time.
+    uc_reg_write(uc, UC_X86_REG_RIP, &CODE_ADDRESS); // Set the instruction pointer back
+    // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly)
+    uc_reg_write(uc, UC_X86_REG_RSI, &INPUT_LOCATION); // argv
+    uc_reg_write(uc, UC_X86_REG_RDI, &EMULATED_ARGC);  // argc == 2
+   
+    // We need a valid c string, make sure it never goes out of bounds.
+    input[input_len-1] = '\0';
+    // Write the testcase to unicorn.
     uc_mem_write(uc, INPUT_LOCATION + INPUT_OFFSET, input, input_len);
+
+    // store input_len for the faux strlen hook
+    current_input_len = input_len;
+
     return true;
 }
 
@@ -187,12 +222,7 @@ int main(int argc, char **argv, char **envp) {
 
     uc_mem_write(uc, 0x10008, "\x16\x00\x01", 3); // little endian of 0x10016, see above
 
-    // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly)
-    uint64_t input_location = INPUT_LOCATION;
-    uc_reg_write(uc, UC_X86_REG_RSI, &input_location); // argv
-    uint64_t emulated_argc = 2;
-    uc_reg_write(uc, UC_X86_REG_RDI, &emulated_argc);  // argc == 2
-   
+
     // If we want tracing output, set the callbacks here
     if (tracing) {
         // tracing all basic blocks with customized callback
@@ -200,6 +230,11 @@ int main(int argc, char **argv, char **envp) {
         uc_hook_add(uc, &hooks[1], UC_HOOK_CODE, hook_code, NULL, BASE_ADDRESS, BASE_ADDRESS + len - 1);
     }
 
+    // Add our strlen hook (for this specific testcase only)
+    int strlen_hook_pos = BASE_ADDRESS + 0x116b;
+    uc_hook strlen_hook;
+    uc_hook_add(uc, &strlen_hook, UC_HOOK_CODE, hook_strlen, NULL, strlen_hook_pos, strlen_hook_pos);
+
     printf("Starting to fuzz :)\n");
     fflush(stdout);
 
@@ -211,9 +246,9 @@ int main(int argc, char **argv, char **envp) {
         &end_address, // Where to exit (this is an array)
         1,  // Count of end addresses
         NULL, // Optional calback to run after each exec
-        false,
-        1, // For persistent mode: How many rounds to run
-        NULL
+        false, // true, if the optional callback should be run also for non-crashes
+        100, // For persistent mode: How many rounds to run
+        NULL // additional data pointer
     );
     switch(afl_ret) {
         case UC_AFL_RET_ERROR:
diff --git a/unicorn_mode/samples/c/persistent_target.c b/unicorn_mode/samples/c/persistent_target.c
new file mode 100644
index 00000000..5b866f86
--- /dev/null
+++ b/unicorn_mode/samples/c/persistent_target.c
@@ -0,0 +1,39 @@
+/*
+ * Sample target file to test afl-unicorn fuzzing capabilities.
+ * This is a very trivial example that will crash pretty easily
+ * in several different exciting ways. 
+ *
+ * Input is assumed to come from a buffer located at DATA_ADDRESS 
+ * (0x00300000), so make sure that your Unicorn emulation of this 
+ * puts user data there.
+ *
+ * Written by Nathan Voss <njvoss99@gmail.com>
+ * Adapted by Lukas Seidel <seidel.1@campus.tu-berlin.de>
+ */
+#include <stdint.h>
+#include <string.h>
+
+
+int main(int argc, char** argv) {
+  if (argc < 2) return -1;
+
+  char *data_buf = argv[1];
+  uint64_t data_len = strlen(data_buf);
+  if (data_len < 20) return -2;
+
+  for (; data_len --> 0 ;) {
+    if (data_len >= 18) continue;
+    if (data_len > 2 && data_len < 18) {
+      ((char *)data_len)[(uint64_t)data_buf] = data_buf[data_len + 1];
+    } else if (data_buf[9] == 0x90 && data_buf[10] != 0x00 && data_buf[11] == 0x90) {
+        // Cause a crash if data[10] is not zero, but [9] and [11] are zero
+        unsigned char invalid_read = *(unsigned char *) 0x00000000;
+    }
+  }
+  if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
+    // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2]
+    unsigned char invalid_read = *(unsigned char *) 0x00000000;
+  } 
+
+  return 0;
+}
diff --git a/unicorn_mode/samples/c/persistent_target_x86_64 b/unicorn_mode/samples/c/persistent_target_x86_64
new file mode 100644
index 00000000..22e04357
--- /dev/null
+++ b/unicorn_mode/samples/c/persistent_target_x86_64
Binary files differdiff --git a/unicorn_mode/samples/persistent/.gitignore b/unicorn_mode/samples/persistent/.gitignore
new file mode 100644
index 00000000..3e446132
--- /dev/null
+++ b/unicorn_mode/samples/persistent/.gitignore
@@ -0,0 +1,3 @@
+harness
+harness-debug
+out
diff --git a/unicorn_mode/samples/persistent/COMPILE.md b/unicorn_mode/samples/persistent/COMPILE.md
new file mode 100644
index 00000000..781f15c0
--- /dev/null
+++ b/unicorn_mode/samples/persistent/COMPILE.md
@@ -0,0 +1,24 @@
+# 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.
+
+## 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
+```
+
+## Compiling persistent_target.c
+
+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.
+
+We then load the binary we execute the main function directly.
diff --git a/unicorn_mode/samples/persistent/Makefile b/unicorn_mode/samples/persistent/Makefile
new file mode 100644
index 00000000..fe100490
--- /dev/null
+++ b/unicorn_mode/samples/persistent/Makefile
@@ -0,0 +1,42 @@
+# UnicornAFL Usage
+# Original Unicorn Example Makefile by Nguyen Anh Quynh <aquynh@gmail.com>, 2015
+# Adapted for AFL++ by domenukk <domenukk@gmail.com>, 2020
+
+UNAME_S := $(shell uname -s)
+
+LIBDIR = ../../unicornafl
+BIN_EXT =
+AR_EXT = a
+
+# Verbose output?
+V ?= 0
+
+CFLAGS += -Wall -Werror -I../../unicornafl/include
+
+LDFLAGS += -L$(LIBDIR) -lpthread -lm
+ifeq ($(UNAME_S), Linux)
+LDFLAGS += -lrt
+endif
+
+ifneq ($(CROSS),)
+CC = $(CROSS)gcc
+endif
+
+.PHONY: all clean
+
+all: harness
+
+clean:		
+	rm -rf *.o harness harness-debug
+
+harness.o: harness.c ../../unicornafl/include/unicorn/*.h
+	${CC} ${CFLAGS} -O3 -c $<
+
+harness-debug.o: harness.c ../../unicornafl/include/unicorn/*.h
+	${CC} ${CFLAGS} -g -c $< -o $@
+
+harness: harness.o
+	${CC} -L${LIBDIR} $< ../../unicornafl/libunicornafl.a $(LDFLAGS) -o $@
+
+debug: harness-debug.o
+	${CC} -L${LIBDIR} $< ../../unicornafl/libunicornafl.a $(LDFLAGS) -o harness-debug
diff --git a/unicorn_mode/samples/persistent/harness.c b/unicorn_mode/samples/persistent/harness.c
new file mode 100644
index 00000000..d8ebffbc
--- /dev/null
+++ b/unicorn_mode/samples/persistent/harness.c
@@ -0,0 +1,269 @@
+/*
+   Persistent test harness for AFL++'s unicornafl c mode.
+
+   This loads the persistent_target.bin binary (precompiled as X86_64 code) into
+   Unicorn's memory map for emulation, places the specified input into
+   the argv buffer (handed in as first parameter), and executes 'main()'.
+   Any crashes during emulation will automatically be handled by the afl-fuzz() function.
+
+   Run under AFL as follows:
+
+   $ cd <afl_path>/unicorn_mode/samples/persistent/
+   $ make
+   $ ../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@
+
+   (Re)run a simgle input with block tracing using:
+
+   $ ./harness -t [inputfile]
+*/
+
+// This is not your everyday Unicorn.
+#define UNICORN_AFL
+
+#include <string.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <unicorn/unicorn.h>
+
+// Path to the file containing the binary to emulate
+#define BINARY_FILE ("persistent_target_x86_64")
+
+// Memory map for the code to be tested
+// Arbitrary address where code to test will be loaded
+static const int64_t BASE_ADDRESS = 0x100000;
+static const int64_t CODE_ADDRESS = 0x101139;
+static const int64_t END_ADDRESS = 0x10120d;
+// Address of the stack (Some random address again)
+static const int64_t STACK_ADDRESS = (((int64_t) 0x01) << 58);
+// Size of the stack (arbitrarily chosen, just make it big enough)
+static const int64_t STACK_SIZE = 0x10000;
+// Location where the input will be placed (make sure the emulated program knows this somehow, too ;) )
+static const int64_t INPUT_LOCATION = 0x10000;
+// Inside the location, we have an ofset in our special case
+static const int64_t INPUT_OFFSET = 0x16;
+// Maximum allowable size of mutated data from AFL
+static const int64_t INPUT_SIZE_MAX = 0x10000;
+// Alignment for unicorn mappings (seems to be needed)
+static const int64_t ALIGNMENT = 0x1000;
+
+// In our special case, we emulate main(), so argc is needed.
+static const uint64_t EMULATED_ARGC = 2;
+
+// The return from our fake strlen
+static size_t current_input_len = 0;
+
+static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
+    printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
+}
+
+static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
+    printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
+}
+
+/*
+The sample uses strlen, since we don't have a loader or libc, we'll fake it.
+We know the strlen will return the lenght of argv[1] that we just planted.
+It will be a lot faster than an actual strlen for this specific purpose.
+*/
+static void hook_strlen(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
+    //Hook
+    //116b:       e8 c0 fe ff ff          call   1030 <strlen@plt>
+    // We place the return at RAX
+    uc_reg_write(uc, UC_X86_REG_RAX, &current_input_len);
+    // We skip the actual call by updating RIP
+    //printf("Strlen hook at addr 0x%lx (size: 0x%x), result: %ld\n", address, size, current_input_len);
+    uint64_t next_addr = address + size; 
+    uc_reg_write(uc, UC_X86_REG_RIP, &next_addr);
+}
+
+/* Unicorn page needs to be 0x1000 aligned, apparently */
+static uint64_t pad(uint64_t size) {
+    if (size % ALIGNMENT == 0) return size;
+    return ((size / ALIGNMENT) + 1) * ALIGNMENT;
+} 
+
+/* returns the filesize in bytes, -1 or error. */
+static off_t afl_mmap_file(char *filename, char **buf_ptr) {
+
+    off_t ret = -1;
+
+    int fd = open(filename, O_RDONLY);
+
+    struct stat st = {0};
+    if (fstat(fd, &st)) goto exit;
+
+    off_t in_len = st.st_size;
+    if (in_len == -1) {
+	/* This can only ever happen on 32 bit if the file is exactly 4gb. */
+	fprintf(stderr, "Filesize of %s too large", filename);
+	goto exit;
+    }
+
+    *buf_ptr = mmap(0, in_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+    if (*buf_ptr != MAP_FAILED) ret = in_len;
+
+exit:
+    close(fd);
+    return ret;
+
+}
+
+/* Place the input at the right spot inside unicorn */
+static bool place_input_callback(
+    uc_engine *uc, 
+    char *input, 
+    size_t input_len, 
+    uint32_t persistent_round, 
+    void *data
+){
+    // printf("Placing input with len %ld to %x\n", input_len, DATA_ADDRESS);
+    if (input_len < 1 || input_len >= INPUT_SIZE_MAX - INPUT_OFFSET) {
+        // Test input too short or too long, ignore this testcase
+        return false;
+    }
+
+    // For persistent mode, we have to set up stack and memory each time.
+    uc_reg_write(uc, UC_X86_REG_RIP, &CODE_ADDRESS); // Set the instruction pointer back
+    // Set up the function parameters accordingly RSI, RDI (see calling convention/disassembly)
+    uc_reg_write(uc, UC_X86_REG_RSI, &INPUT_LOCATION); // argv
+    uc_reg_write(uc, UC_X86_REG_RDI, &EMULATED_ARGC);  // argc == 2
+   
+    // We need a valid c string, make sure it never goes out of bounds.
+    input[input_len-1] = '\0';
+    // Write the testcase to unicorn.
+    uc_mem_write(uc, INPUT_LOCATION + INPUT_OFFSET, input, input_len);
+
+    // store input_len for the faux strlen hook
+    current_input_len = input_len;
+
+    return true;
+}
+
+static void mem_map_checked(uc_engine *uc, uint64_t addr, size_t size, uint32_t mode) {
+    size = pad(size);
+    //printf("SIZE %lx, align: %lx\n", size, ALIGNMENT);
+    uc_err err = uc_mem_map(uc, addr, size, mode);
+    if (err != UC_ERR_OK) {
+        printf("Error mapping %ld bytes at 0x%lx: %s (mode: %d)\n", size, addr, uc_strerror(err), mode);
+        exit(1);
+    }
+}
+
+int main(int argc, char **argv, char **envp) {
+    if (argc == 1) {
+        printf("Test harness for simple_target.bin. Usage: harness [-t] <inputfile>\n");
+        exit(1);
+    }
+    bool tracing = false;
+    char *filename = argv[1];
+    if (argc > 2 && !strcmp(argv[1], "-t")) {
+        tracing = true;
+        filename = argv[2];
+    }
+
+    uc_engine *uc;
+    uc_err err;
+    uc_hook hooks[2];
+    char *file_contents;
+
+    // Initialize emulator in X86_64 mode
+    err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
+    if (err) {
+        printf("Failed on uc_open() with error returned: %u (%s)\n",
+                err, uc_strerror(err));
+        return -1;
+    }
+
+    printf("Loading data input from %s\n", BINARY_FILE);
+    off_t len = afl_mmap_file(BINARY_FILE, &file_contents);
+    if (len < 0) {
+        perror("Could not read binary to emulate");
+        return -2;
+    }
+    if (len == 0) {
+	fprintf(stderr, "File at '%s' is empty\n", BINARY_FILE);
+	return -3;
+    }
+
+    // Map memory.
+    mem_map_checked(uc, BASE_ADDRESS, len, UC_PROT_ALL);
+    printf("Len: %lx", len);
+    fflush(stdout);
+
+    // write machine code to be emulated to memory
+    if (uc_mem_write(uc, BASE_ADDRESS, file_contents, len) != UC_ERR_OK) {
+        printf("Error writing to CODE");
+    }
+
+    // Release copied contents
+    munmap(file_contents, len);
+
+    // Set the program counter to the start of the code
+    uint64_t start_address = CODE_ADDRESS;      // address of entry point of main()
+    uint64_t end_address = END_ADDRESS; // Address of last instruction in main()
+    uc_reg_write(uc, UC_X86_REG_RIP, &start_address); // address of entry point of main()
+    
+    // Setup the Stack
+    mem_map_checked(uc, STACK_ADDRESS - STACK_SIZE, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE);
+    uint64_t stack_val = STACK_ADDRESS;
+    printf("%ld", stack_val);
+    uc_reg_write(uc, UC_X86_REG_RSP, &stack_val);
+
+    // reserve some space for our input data
+    mem_map_checked(uc, INPUT_LOCATION, INPUT_SIZE_MAX, UC_PROT_READ);
+
+    // build a "dummy" argv with lenth 2 at 0x10000: 
+    // 0x10000 argv[0]  NULL
+    // 0x10008 argv[1]  (char *)0x10016 --. points to the next offset.
+    // 0x10016 argv[1][0], ...          <-^ contains the acutal input data. (INPUT_LOCATION + INPUT_OFFSET)
+
+    uc_mem_write(uc, 0x10008, "\x16\x00\x01", 3); // little endian of 0x10016, see above
+
+
+    // If we want tracing output, set the callbacks here
+    if (tracing) {
+        // tracing all basic blocks with customized callback
+        uc_hook_add(uc, &hooks[0], UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
+        uc_hook_add(uc, &hooks[1], UC_HOOK_CODE, hook_code, NULL, BASE_ADDRESS, BASE_ADDRESS + len - 1);
+    }
+
+    // Add our strlen hook (for this specific testcase only)
+    int strlen_hook_pos = BASE_ADDRESS + 0x116b;
+    uc_hook strlen_hook;
+    uc_hook_add(uc, &strlen_hook, UC_HOOK_CODE, hook_strlen, NULL, strlen_hook_pos, strlen_hook_pos);
+
+    printf("Starting to fuzz :)\n");
+    fflush(stdout);
+
+    // let's gooo
+    uc_afl_ret afl_ret = uc_afl_fuzz(
+        uc, // The unicorn instance we prepared
+        filename, // Filename of the input to process. In AFL this is usually the '@@' placeholder, outside it's any input file.
+        place_input_callback, // Callback that places the input (automatically loaded from the file at filename) in the unicorninstance
+        &end_address, // Where to exit (this is an array)
+        1,  // Count of end addresses
+        NULL, // Optional calback to run after each exec
+        false, // true, if the optional callback should be run also for non-crashes
+        1000, // For persistent mode: How many rounds to run
+        NULL // additional data pointer
+    );
+    switch(afl_ret) {
+        case UC_AFL_RET_ERROR:
+            printf("Error starting to fuzz");
+            return -3;
+            break;
+        case UC_AFL_RET_NO_AFL:
+            printf("No AFL attached - We are done with a single run.");
+            break;
+        default:
+            break;
+    } 
+    return 0;
+}
diff --git a/unicorn_mode/samples/persistent/persistent_target.c b/unicorn_mode/samples/persistent/persistent_target.c
new file mode 100644
index 00000000..5b866f86
--- /dev/null
+++ b/unicorn_mode/samples/persistent/persistent_target.c
@@ -0,0 +1,39 @@
+/*
+ * Sample target file to test afl-unicorn fuzzing capabilities.
+ * This is a very trivial example that will crash pretty easily
+ * in several different exciting ways. 
+ *
+ * Input is assumed to come from a buffer located at DATA_ADDRESS 
+ * (0x00300000), so make sure that your Unicorn emulation of this 
+ * puts user data there.
+ *
+ * Written by Nathan Voss <njvoss99@gmail.com>
+ * Adapted by Lukas Seidel <seidel.1@campus.tu-berlin.de>
+ */
+#include <stdint.h>
+#include <string.h>
+
+
+int main(int argc, char** argv) {
+  if (argc < 2) return -1;
+
+  char *data_buf = argv[1];
+  uint64_t data_len = strlen(data_buf);
+  if (data_len < 20) return -2;
+
+  for (; data_len --> 0 ;) {
+    if (data_len >= 18) continue;
+    if (data_len > 2 && data_len < 18) {
+      ((char *)data_len)[(uint64_t)data_buf] = data_buf[data_len + 1];
+    } else if (data_buf[9] == 0x90 && data_buf[10] != 0x00 && data_buf[11] == 0x90) {
+        // Cause a crash if data[10] is not zero, but [9] and [11] are zero
+        unsigned char invalid_read = *(unsigned char *) 0x00000000;
+    }
+  }
+  if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
+    // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2]
+    unsigned char invalid_read = *(unsigned char *) 0x00000000;
+  } 
+
+  return 0;
+}
diff --git a/unicorn_mode/samples/persistent/persistent_target_x86_64 b/unicorn_mode/samples/persistent/persistent_target_x86_64
new file mode 100644
index 00000000..22e04357
--- /dev/null
+++ b/unicorn_mode/samples/persistent/persistent_target_x86_64
Binary files differdiff --git a/unicorn_mode/samples/persistent/sample_all.sh b/unicorn_mode/samples/persistent/sample_all.sh
new file mode 100644
index 00000000..01daf365
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_all.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+[ -z "${UNAME}" ] && UNAME=$(uname)
+
+DIR=`dirname $0`
+
+if [ "$UNAME" = Darwin ]; then
+  export DYLD_LIBRARY_PATH=../../unicorn
+else
+  export LD_LIBRARY_PATH=../../unicorn
+fi
+
+
+
+if [ ! test -e $DIR/harness]; then
+  echo "[!] harness not found in $DIR"
+  exit 1
+fi
\ No newline at end of file
diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample1.bin b/unicorn_mode/samples/persistent/sample_inputs/sample1.bin
new file mode 100644
index 00000000..85df5078
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_inputs/sample1.bin
@@ -0,0 +1 @@
+abcd
\ No newline at end of file
diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample2.bin b/unicorn_mode/samples/persistent/sample_inputs/sample2.bin
new file mode 100644
index 00000000..f76dd238
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_inputs/sample2.bin
Binary files differdiff --git a/unicorn_mode/samples/persistent/sample_inputs/sample3.bin b/unicorn_mode/samples/persistent/sample_inputs/sample3.bin
new file mode 100644
index 00000000..6b2aaa76
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_inputs/sample3.bin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample4.bin b/unicorn_mode/samples/persistent/sample_inputs/sample4.bin
new file mode 100644
index 00000000..71bd63e6
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_inputs/sample4.bin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/unicorn_mode/samples/persistent/sample_inputs/sample5.bin b/unicorn_mode/samples/persistent/sample_inputs/sample5.bin
new file mode 100644
index 00000000..aed2973e
--- /dev/null
+++ b/unicorn_mode/samples/persistent/sample_inputs/sample5.bin
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/unicorn_mode/samples/c/simple_target.c b/unicorn_mode/samples/persistent/simple_target_noncrashing.c
index dbf10911..00764473 100644
--- a/unicorn_mode/samples/c/simple_target.c
+++ b/unicorn_mode/samples/persistent/simple_target_noncrashing.c
@@ -19,12 +19,11 @@ int main(int argc, char** argv) {
 
   char *data_buf = argv[1];
 
+  if len(data_buf < 20) {
   if (data_buf[20] != 0) {
-    // Cause an 'invalid read' crash if data[0..3] == '\x01\x02\x03\x04'
-    unsigned char invalid_read = *(unsigned char *) 0x00000000;
+    printf("Not crashing");
   } else if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
-    // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2]
-    unsigned char invalid_read = *(unsigned char *) 0x00000000;
+    printf("Also not crashing with databuf[0] == %c", data_buf[0])
   } else if (data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) {
     // Cause a crash if data[10] is not zero, but [9] and [11] are zero
     unsigned char invalid_read = *(unsigned char *) 0x00000000;
diff --git a/unicorn_mode/samples/persistent/simple_target_x86_64 b/unicorn_mode/samples/persistent/simple_target_x86_64
new file mode 100644
index 00000000..560264fd
--- /dev/null
+++ b/unicorn_mode/samples/persistent/simple_target_x86_64
Binary files differ