about summary refs log tree commit diff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/README.md54
-rw-r--r--utils/afl_frida/GNUmakefile23
-rw-r--r--utils/afl_frida/Makefile2
-rw-r--r--utils/afl_frida/README.md34
-rw-r--r--utils/afl_frida/afl-frida.c397
-rw-r--r--utils/afl_frida/afl-frida.h53
-rw-r--r--utils/afl_frida/android/README.md1
-rw-r--r--utils/afl_frida/android/frida-gum-example.c130
-rw-r--r--utils/afl_frida/libtestinstr.c35
-rw-r--r--utils/afl_network_proxy/GNUmakefile44
-rw-r--r--utils/afl_network_proxy/Makefile2
-rw-r--r--utils/afl_network_proxy/README.md61
-rw-r--r--utils/afl_network_proxy/afl-network-client.c415
-rw-r--r--utils/afl_network_proxy/afl-network-server.c685
-rw-r--r--utils/afl_proxy/Makefile7
-rw-r--r--utils/afl_proxy/README.md9
-rw-r--r--utils/afl_proxy/afl-proxy.c238
-rw-r--r--utils/afl_untracer/Makefile16
-rw-r--r--utils/afl_untracer/README.md60
-rw-r--r--utils/afl_untracer/TODO2
-rw-r--r--utils/afl_untracer/afl-untracer.c777
-rw-r--r--utils/afl_untracer/ghidra_get_patchpoints.java84
-rw-r--r--utils/afl_untracer/ida_get_patchpoints.py63
-rw-r--r--utils/afl_untracer/libtestinstr.c35
-rw-r--r--utils/afl_untracer/patches.txt34
-rw-r--r--utils/aflpp_driver/GNUmakefile46
-rw-r--r--utils/aflpp_driver/Makefile2
-rw-r--r--utils/aflpp_driver/aflpp_driver.c284
-rw-r--r--utils/aflpp_driver/aflpp_driver_test.c26
-rw-r--r--utils/aflpp_driver/aflpp_qemu_driver.c38
-rw-r--r--utils/aflpp_driver/aflpp_qemu_driver_hook.c22
-rwxr-xr-xutils/analysis_scripts/queue2csv.sh122
-rw-r--r--utils/argv_fuzzing/Makefile58
-rw-r--r--utils/argv_fuzzing/README.md16
-rw-r--r--utils/argv_fuzzing/argv-fuzz-inl.h90
-rw-r--r--utils/argv_fuzzing/argvfuzz.c49
-rwxr-xr-xutils/asan_cgroups/limit_memory.sh157
-rw-r--r--utils/bash_shellshock/shellshock-fuzz.diff59
-rw-r--r--utils/canvas_harness/canvas_harness.html170
-rwxr-xr-xutils/clang_asm_normalize/as75
-rwxr-xr-xutils/crash_triage/triage_crashes.sh115
-rw-r--r--utils/custom_mutators/Makefile7
-rw-r--r--utils/custom_mutators/README.md35
-rw-r--r--utils/custom_mutators/XmlMutatorMin.py348
-rw-r--r--utils/custom_mutators/common.py40
-rw-r--r--utils/custom_mutators/custom_mutator_helpers.h342
-rw-r--r--utils/custom_mutators/example.c376
-rw-r--r--utils/custom_mutators/example.py187
-rw-r--r--utils/custom_mutators/post_library_gif.so.c165
-rw-r--r--utils/custom_mutators/post_library_png.so.c163
-rw-r--r--utils/custom_mutators/simple-chunk-replace.py66
-rw-r--r--utils/custom_mutators/simple_example.c74
-rw-r--r--utils/custom_mutators/wrapper_afl_min.py123
-rw-r--r--utils/defork/Makefile64
-rw-r--r--utils/defork/README.md11
-rw-r--r--utils/defork/defork.c51
-rw-r--r--utils/defork/forking_target.c49
-rwxr-xr-xutils/distributed_fuzzing/sync_script.sh97
-rw-r--r--utils/libdislocator/Makefile43
-rw-r--r--utils/libdislocator/README.md68
-rw-r--r--utils/libdislocator/libdislocator.so.c546
-rw-r--r--utils/libpng_no_checksum/libpng-nocrc.patch15
-rw-r--r--utils/libtokencap/Makefile94
-rw-r--r--utils/libtokencap/README.md69
-rw-r--r--utils/libtokencap/libtokencap.so.c794
-rw-r--r--utils/persistent_mode/Makefile10
-rw-r--r--utils/persistent_mode/persistent_demo.c118
-rw-r--r--utils/persistent_mode/persistent_demo_new.c123
-rw-r--r--utils/persistent_mode/test-instr.c75
-rwxr-xr-xutils/qbdi_mode/README.md199
-rw-r--r--utils/qbdi_mode/assets/screen1.pngbin0 -> 88333 bytes
-rwxr-xr-xutils/qbdi_mode/build.sh57
-rwxr-xr-xutils/qbdi_mode/demo-so.c41
-rwxr-xr-xutils/qbdi_mode/template.cpp251
-rw-r--r--utils/qemu_persistent_hook/Makefile6
-rw-r--r--utils/qemu_persistent_hook/README.md19
-rw-r--r--utils/qemu_persistent_hook/read_into_rdi.c34
-rw-r--r--utils/qemu_persistent_hook/test.c35
-rw-r--r--utils/socket_fuzzing/Makefile61
-rw-r--r--utils/socket_fuzzing/README.md11
-rw-r--r--utils/socket_fuzzing/socketfuzz.c110
81 files changed, 9567 insertions, 0 deletions
diff --git a/utils/README.md b/utils/README.md
new file mode 100644
index 00000000..336b6b6c
--- /dev/null
+++ b/utils/README.md
@@ -0,0 +1,54 @@
+# AFL++ Examples
+
+Here's a quick overview of the stuff you can find in this directory:
+
+  - afl_network_proxy    - fuzz a target over the network: afl-fuzz on
+                           a host, target on an embedded system.
+
+  - afl_proxy            - skeleton file example to show how to fuzz
+                           something where you gather coverage data via
+                           different means, e.g. hw debugger
+
+  - afl_untracer         - fuzz binary-only libraries much faster but with
+                           less coverage than qemu_mode
+
+  - argv_fuzzing         - a simple wrapper to allow cmdline to be fuzzed
+                           (e.g., to test setuid programs).
+
+  - asan_cgroups         - a contributed script to simplify fuzzing ASAN
+                           binaries with robust memory limits on Linux.
+
+  - bash_shellshock      - a simple hack used to find a bunch of
+                           post-Shellshock bugs in bash.
+
+  - canvas_harness       - a test harness used to find browser bugs with a
+                           corpus generated using simple image parsing
+                           binaries & afl-fuzz.
+
+  - clang_asm_normalize  - a script that makes it easy to instrument
+                           hand-written assembly, provided that you have clang.
+
+  - crash_triage         - a very rudimentary example of how to annotate crashes
+                           with additional gdb metadata.
+
+  - custom_mutators      - examples for the afl++ custom mutator interface in
+                           C and Python
+
+  - distributed_fuzzing  - a sample script for synchronizing fuzzer instances
+                           across multiple machines (see parallel_fuzzing.md).
+
+  - libpng_no_checksum   - a sample patch for removing CRC checks in libpng.
+
+  - persistent_mode      - an example of how to use the LLVM persistent process
+                           mode to speed up certain fuzzing jobs.
+
+  - socket_fuzzing       - a LD_PRELOAD library 'redirects' a socket to stdin
+                           for fuzzing access with afl++
+
+Note that the minimize_corpus.sh tool has graduated from the utils/
+directory and is now available as ../afl-cmin. The LLVM mode has likewise
+graduated to ../instrumentation/*.
+
+Most of the tools in this directory are meant chiefly as examples that need to
+be tweaked for your specific needs. They come with some basic documentation,
+but are not necessarily production-grade.
diff --git a/utils/afl_frida/GNUmakefile b/utils/afl_frida/GNUmakefile
new file mode 100644
index 00000000..8b56415b
--- /dev/null
+++ b/utils/afl_frida/GNUmakefile
@@ -0,0 +1,23 @@
+ifdef DEBUG
+  OPT=-O0 -D_DEBUG=\"1\"
+else
+  OPT=-O3 -funroll-loops
+endif
+
+all:	afl-frida libtestinstr.so
+
+libfrida-gum.a:
+	@echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest
+	@exit 1
+	
+afl-frida:	afl-frida.c libfrida-gum.a
+	$(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-compiler-rt.o libfrida-gum.a -ldl -lresolv -pthread
+
+libtestinstr.so:        libtestinstr.c
+	$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
+
+clean:
+	rm -f afl-frida *~ core *.o libtestinstr.so
+
+deepclean: clean
+	rm -f libfrida-gum.a frida-gum*
diff --git a/utils/afl_frida/Makefile b/utils/afl_frida/Makefile
new file mode 100644
index 00000000..0b306dde
--- /dev/null
+++ b/utils/afl_frida/Makefile
@@ -0,0 +1,2 @@
+all:
+	@echo please use GNU make, thanks!
diff --git a/utils/afl_frida/README.md b/utils/afl_frida/README.md
new file mode 100644
index 00000000..68b62009
--- /dev/null
+++ b/utils/afl_frida/README.md
@@ -0,0 +1,34 @@
+# afl-frida - faster fuzzing of binary-only libraries
+
+## Introduction
+
+afl-frida is an example skeleton file which can easily be used to fuzz
+a closed source library.
+
+It requires less memory and is x5-10 faster than qemu_mode but does not
+provide interesting features like compcov or cmplog.
+
+## How-to
+
+### Modify afl-frida.c
+
+Read and modify afl-frida.c then `make`.
+To adapt afl-frida.c to your needs, read the header of the file and then
+search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
+
+### Fuzzing
+
+Example (after modifying afl-frida.c to your needs and compile it):
+```
+LD_LIBRARY_PATH=/path/to/the/target/library/ afl-fuzz -i in -o out -- ./afl-frida
+```
+(or even remote via afl-network-proxy).
+
+# Speed and stability
+
+The speed is very good, about x12 of fork() qemu_mode.
+However the stability is low. Reason is currently unknown.
+
+# Background
+
+This code is copied for a larger part from https://github.com/meme/hotwax
diff --git a/utils/afl_frida/afl-frida.c b/utils/afl_frida/afl-frida.c
new file mode 100644
index 00000000..711d8f33
--- /dev/null
+++ b/utils/afl_frida/afl-frida.c
@@ -0,0 +1,397 @@
+/*
+   american fuzzy lop++ - afl-frida skeleton example
+   -------------------------------------------------
+
+   Copyright 2020 AFLplusplus Project. All rights reserved.
+
+   Written mostly by meme -> https://github.com/meme/hotwax
+
+   Modifications by Marc Heuse <mh@mh-sec.de>
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   HOW-TO
+   ======
+
+   You only need to change the following:
+
+   1. set the defines and function call parameters.
+   2. dl load the library you want to fuzz, lookup the functions you need
+      and setup the calls to these.
+   3. in the while loop you call the functions in the necessary order -
+      incl the cleanup. the cleanup is important!
+
+   Just look these steps up in the code, look for "// STEP x:"
+
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/shm.h>
+#include <dlfcn.h>
+
+#ifdef __APPLE__
+  #include <mach/mach.h>
+  #include <mach-o/dyld_images.h>
+#else
+  #include <sys/wait.h>
+  #include <sys/personality.h>
+#endif
+
+int debug = 0;
+
+// STEP 1:
+
+// The presets are for the example libtestinstr.so:
+
+/* What is the name of the library to fuzz */
+#define TARGET_LIBRARY "libtestinstr.so"
+
+/* What is the name of the function to fuzz */
+#define TARGET_FUNCTION "testinstr"
+
+/* here you need to specify the parameter for the target function */
+static void *(*o_function)(uint8_t *, int);
+
+// END STEP 1
+
+#include "frida-gum.h"
+
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data);
+void afl_setup(void);
+void afl_start_forkserver(void);
+int  __afl_persistent_loop(unsigned int max_cnt);
+
+#include "../../config.h"
+
+// Shared memory fuzzing.
+int                   __afl_sharedmem_fuzzing = 1;
+extern unsigned int * __afl_fuzz_len;
+extern unsigned char *__afl_fuzz_ptr;
+
+// Notify AFL about persistent mode.
+static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##\0";
+int                  __afl_persistent_loop(unsigned int);
+
+// Notify AFL about deferred forkserver.
+static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##\0";
+void                 __afl_manual_init();
+
+// Because we do our own logging.
+extern uint8_t *        __afl_area_ptr;
+static __thread guint64 previous_pc;
+
+// Frida stuff below.
+typedef struct {
+
+  GumAddress base_address;
+  guint64    code_start, code_end;
+  GumAddress current_log_impl;
+  uint64_t   afl_prev_loc;
+
+} range_t;
+
+inline static void afl_maybe_log(guint64 current_pc) {
+
+  // fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc);
+
+  current_pc = (current_pc >> 4) ^ (current_pc << 8);
+  current_pc &= MAP_SIZE - 1;
+
+  __afl_area_ptr[current_pc ^ previous_pc]++;
+  previous_pc = current_pc >> 1;
+
+}
+
+#if GUM_NATIVE_CPU == GUM_CPU_AMD64
+
+static const guint8 afl_maybe_log_code[] = {
+
+    0x9c,  // pushfq
+    0x50,  // push rax
+    0x51,  // push rcx
+    0x52,  // push rdx
+    0x56,  // push rsi
+
+    0x89, 0xf8,                                // mov eax, edi
+    0xc1, 0xe0, 0x08,                          // shl eax, 8
+    0xc1, 0xef, 0x04,                          // shr edi, 4
+    0x31, 0xc7,                                // xor edi, eax
+    0x0f, 0xb7, 0xc7,                          // movzx eax, di
+    0x48, 0x8d, 0x0d, 0x30, 0x00, 0x00, 0x00,  // lea rcx, sym._afl_area_ptr_ptr
+    0x48, 0x8b, 0x09,                          // mov rcx, qword [rcx]
+    0x48, 0x8b, 0x09,                          // mov rcx, qword [rcx]
+    0x48, 0x8d, 0x15, 0x1b, 0x00, 0x00, 0x00,  // lea rdx, sym._afl_prev_loc_ptr
+    0x48, 0x8b, 0x32,                          // mov rsi, qword [rdx]
+    0x48, 0x8b, 0x36,                          // mov rsi, qword [rsi]
+    0x48, 0x31, 0xc6,                          // xor rsi, rax
+    0xfe, 0x04, 0x31,                          // inc byte [rcx + rsi]
+
+    0x48, 0xd1, 0xe8,  // shr rax, 1
+    0x48, 0x8b, 0x0a,  // mov rcx, qword [rdx]
+    0x48, 0x89, 0x01,  // mov qword [rcx], rax
+
+    0x5e,  // pop rsi
+    0x5a,  // pop rdx
+    0x59,  // pop rcx
+    0x58,  // pop rax
+    0x9d,  // popfq
+
+    0xc3,  // ret
+           // Read-only data goes here:
+           // uint64_t* afl_prev_loc_ptr
+           // uint8_t** afl_area_ptr_ptr
+           // unsigned int afl_instr_rms
+
+};
+
+#else
+
+static void on_basic_block(GumCpuContext *context, gpointer user_data) {
+
+  afl_maybe_log((guint64)user_data);
+
+}
+
+#endif
+
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data) {
+
+  range_t *range = (range_t *)user_data;
+
+  const cs_insn *instr;
+  gboolean       begin = TRUE;
+  while (gum_stalker_iterator_next(iterator, &instr)) {
+
+    if (begin) {
+
+      if (instr->address >= range->code_start &&
+          instr->address <= range->code_end) {
+
+#if GUM_NATIVE_CPU == GUM_CPU_AMD64
+        GumX86Writer *cw = output->writer.x86;
+        if (range->current_log_impl == 0 ||
+            !gum_x86_writer_can_branch_directly_between(
+                cw->pc, range->current_log_impl) ||
+            !gum_x86_writer_can_branch_directly_between(
+                cw->pc + 128, range->current_log_impl)) {
+
+          gconstpointer after_log_impl = cw->code + 1;
+
+          gum_x86_writer_put_jmp_near_label(cw, after_log_impl);
+
+          range->current_log_impl = cw->pc;
+          gum_x86_writer_put_bytes(cw, afl_maybe_log_code,
+                                   sizeof(afl_maybe_log_code));
+
+          uint64_t *afl_prev_loc_ptr = &range->afl_prev_loc;
+          uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
+          gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
+                                   sizeof(afl_prev_loc_ptr));
+          gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
+                                   sizeof(afl_area_ptr_ptr));
+          gum_x86_writer_put_label(cw, after_log_impl);
+
+        }
+
+        gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                              -GUM_RED_ZONE_SIZE);
+        gum_x86_writer_put_push_reg(cw, GUM_REG_RDI);
+        gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI,
+                                           GUM_ADDRESS(instr->address));
+        gum_x86_writer_put_call_address(cw, range->current_log_impl);
+        gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI);
+        gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+                                              GUM_RED_ZONE_SIZE);
+#else
+        gum_stalker_iterator_put_callout(iterator, on_basic_block,
+                                         (gpointer)instr->address, NULL);
+#endif
+        begin = FALSE;
+
+      }
+
+    }
+
+    gum_stalker_iterator_keep(iterator);
+
+  }
+
+}
+
+/* Because this CAN be called more than once, it will return the LAST range */
+static int enumerate_ranges(const GumRangeDetails *details,
+                            gpointer               user_data) {
+
+  GumMemoryRange *code_range = (GumMemoryRange *)user_data;
+  memcpy(code_range, details->range, sizeof(*code_range));
+  return 0;
+
+}
+
+int main(int argc, char **argv) {
+
+#ifndef __APPLE__
+  (void)personality(ADDR_NO_RANDOMIZE);  // disable ASLR
+#endif
+
+  // STEP 2: load the library you want to fuzz and lookup the functions,
+  //         inclusive of the cleanup functions.
+  //         If there is just one function, then there is nothing to change
+  //         or add here.
+
+  void *dl = NULL;
+  if (argc > 2) {
+
+    dl = dlopen(argv[1], RTLD_LAZY);
+
+  } else {
+
+    dl = dlopen(TARGET_LIBRARY, RTLD_LAZY);
+
+  }
+
+  if (!dl) {
+
+    if (argc > 2)
+      fprintf(stderr, "Could not load %s\n", argv[1]);
+    else
+      fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY);
+    exit(-1);
+
+  }
+
+  if (argc > 2)
+    o_function = dlsym(dl, argv[2]);
+  else
+    o_function = dlsym(dl, TARGET_FUNCTION);
+  if (!o_function) {
+
+    if (argc > 2)
+      fprintf(stderr, "Could not find function %s\n", argv[2]);
+    else
+      fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION);
+    exit(-1);
+
+  }
+
+  // END STEP 2
+
+  if (!getenv("AFL_FRIDA_TEST_INPUT")) {
+
+    gum_init_embedded();
+    if (!gum_stalker_is_supported()) {
+
+      gum_deinit_embedded();
+      return 1;
+
+    }
+
+    GumStalker *stalker = gum_stalker_new();
+
+    GumAddress base_address;
+    if (argc > 2)
+      base_address = gum_module_find_base_address(argv[1]);
+    else
+      base_address = gum_module_find_base_address(TARGET_LIBRARY);
+    GumMemoryRange code_range;
+    if (argc > 2)
+      gum_module_enumerate_ranges(argv[1], GUM_PAGE_RX, enumerate_ranges,
+                                  &code_range);
+    else
+      gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges,
+                                  &code_range);
+
+    guint64 code_start = code_range.base_address;
+    guint64 code_end = code_range.base_address + code_range.size;
+    range_t instr_range = {0, code_start, code_end, 0, 0};
+
+    printf("Frida instrumentation: base=0x%lx instrumenting=0x%lx-%lx\n",
+           base_address, code_start, code_end);
+    if (!code_start || !code_end) {
+
+      if (argc > 2)
+        fprintf(stderr, "Error: no valid memory address found for %s\n",
+                argv[1]);
+      else
+        fprintf(stderr, "Error: no valid memory address found for %s\n",
+                TARGET_LIBRARY);
+      exit(-1);
+
+    }
+
+    GumStalkerTransformer *transformer =
+        gum_stalker_transformer_make_from_callback(instr_basic_block,
+                                                   &instr_range, NULL);
+
+    // to ensure that the signatures are not optimized out
+    memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
+    memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR,
+           sizeof(AFL_DEFER_FORKSVR));
+    __afl_manual_init();
+
+    //
+    // any expensive target library initialization that has to be done just once
+    // - put that here
+    //
+
+    gum_stalker_follow_me(stalker, transformer, NULL);
+
+    while (__afl_persistent_loop(UINT32_MAX) != 0) {
+
+      previous_pc = 0;  // Required!
+
+#ifdef _DEBUG
+      fprintf(stderr, "CLIENT crc: %016llx len: %u\n",
+              hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len);
+      fprintf(stderr, "RECV:");
+      for (int i = 0; i < *__afl_fuzz_len; i++)
+        fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
+      fprintf(stderr, "\n");
+#endif
+
+      // STEP 3: ensure the minimum length is present and setup the target
+      //         function to fuzz.
+
+      if (*__afl_fuzz_len > 0) {
+
+        __afl_fuzz_ptr[*__afl_fuzz_len] = 0;  // if you need to null terminate
+        (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len);
+
+      }
+
+      // END STEP 3
+
+    }
+
+    gum_stalker_unfollow_me(stalker);
+
+    while (gum_stalker_garbage_collect(stalker))
+      g_usleep(10000);
+
+    g_object_unref(stalker);
+    g_object_unref(transformer);
+    gum_deinit_embedded();
+
+  } else {
+
+    char buf[8 * 1024] = {0};
+    int  count = read(0, buf, sizeof(buf));
+    buf[8 * 1024 - 1] = '\0';
+    (*o_function)(buf, count);
+
+  }
+
+  return 0;
+
+}
+
diff --git a/utils/afl_frida/afl-frida.h b/utils/afl_frida/afl-frida.h
new file mode 100644
index 00000000..efa3440f
--- /dev/null
+++ b/utils/afl_frida/afl-frida.h
@@ -0,0 +1,53 @@
+extern int is_persistent;
+
+G_BEGIN_DECLS
+
+#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type())
+
+G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM,
+                     FAKE_EVENT_SINK, GObject)
+
+struct _GumFakeEventSink {
+
+  GObject      parent;
+  GumEventType mask;
+
+};
+
+GumEventSink *gum_fake_event_sink_new(void);
+void          gum_fake_event_sink_reset(GumFakeEventSink *self);
+
+G_END_DECLS
+
+typedef struct {
+
+  GumAddress base_address;
+  guint64    code_start, code_end;
+
+} range_t;
+
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data);
+#pragma once
+
+void afl_setup(void);
+void afl_start_forkserver(void);
+int  __afl_persistent_loop(unsigned int max_cnt);
+
+inline static inline void afl_maybe_log(guint64 current_pc) {
+
+  extern unsigned int afl_instr_rms;
+  extern uint8_t *    afl_area_ptr;
+
+  static __thread guint64 previous_pc;
+
+  current_pc = (current_pc >> 4) ^ (current_pc << 8);
+  current_pc &= MAP_SIZE - 1;
+
+  if (current_pc >= afl_instr_rms) return;
+
+  afl_area_ptr[current_pc ^ previous_pc]++;
+  previous_pc = current_pc >> 1;
+
+}
+
diff --git a/utils/afl_frida/android/README.md b/utils/afl_frida/android/README.md
new file mode 100644
index 00000000..044b48a1
--- /dev/null
+++ b/utils/afl_frida/android/README.md
@@ -0,0 +1 @@
+For android, frida-gum package (ex. https://github.com/frida/frida/releases/download/14.2.6/frida-gum-devkit-14.2.6-android-arm64.tar.xz) is needed to be extracted in the directory.
diff --git a/utils/afl_frida/android/frida-gum-example.c b/utils/afl_frida/android/frida-gum-example.c
new file mode 100644
index 00000000..14d98248
--- /dev/null
+++ b/utils/afl_frida/android/frida-gum-example.c
@@ -0,0 +1,130 @@
+/*
+ * Compile with:
+ *
+ * clang -fPIC -DANDROID -ffunction-sections -fdata-sections -Os -pipe -g3 frida-gum-example.c -o frida-gum-example -L. -lfrida-gum -llog -ldl -lm -pthread -Wl,--gc-sections,-z,noexecstack,-z,relro,-z,now -fuse-ld=gold -fuse-ld=gold -Wl,--icf=all
+ *
+ * Visit https://frida.re to learn more about Frida.
+ */
+
+#include "frida-gum.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+typedef struct _ExampleListener ExampleListener;
+typedef enum _ExampleHookId ExampleHookId;
+
+struct _ExampleListener
+{
+  GObject parent;
+
+  guint num_calls;
+};
+
+enum _ExampleHookId
+{
+  EXAMPLE_HOOK_OPEN,
+  EXAMPLE_HOOK_CLOSE
+};
+
+static void example_listener_iface_init (gpointer g_iface, gpointer iface_data);
+
+#define EXAMPLE_TYPE_LISTENER (example_listener_get_type ())
+G_DECLARE_FINAL_TYPE (ExampleListener, example_listener, EXAMPLE, LISTENER, GObject)
+G_DEFINE_TYPE_EXTENDED (ExampleListener,
+                        example_listener,
+                        G_TYPE_OBJECT,
+                        0,
+                        G_IMPLEMENT_INTERFACE (GUM_TYPE_INVOCATION_LISTENER,
+                            example_listener_iface_init))
+
+int
+main (int argc,
+      char * argv[])
+{
+  GumInterceptor * interceptor;
+  GumInvocationListener * listener;
+
+  gum_init_embedded ();
+
+  interceptor = gum_interceptor_obtain ();
+  listener = g_object_new (EXAMPLE_TYPE_LISTENER, NULL);
+
+  gum_interceptor_begin_transaction (interceptor);
+  gum_interceptor_attach (interceptor,
+      GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "open")),
+      listener,
+      GSIZE_TO_POINTER (EXAMPLE_HOOK_OPEN));
+  gum_interceptor_attach (interceptor,
+      GSIZE_TO_POINTER (gum_module_find_export_by_name (NULL, "close")),
+      listener,
+      GSIZE_TO_POINTER (EXAMPLE_HOOK_CLOSE));
+  gum_interceptor_end_transaction (interceptor);
+
+  close (open ("/etc/hosts", O_RDONLY));
+  close (open ("/etc/fstab", O_RDONLY));
+
+  g_print ("[*] listener got %u calls\n", EXAMPLE_LISTENER (listener)->num_calls);
+
+  gum_interceptor_detach (interceptor, listener);
+
+  close (open ("/etc/hosts", O_RDONLY));
+  close (open ("/etc/fstab", O_RDONLY));
+
+  g_print ("[*] listener still has %u calls\n", EXAMPLE_LISTENER (listener)->num_calls);
+
+  g_object_unref (listener);
+  g_object_unref (interceptor);
+
+  gum_deinit_embedded ();
+
+  return 0;
+}
+
+static void
+example_listener_on_enter (GumInvocationListener * listener,
+                           GumInvocationContext * ic)
+{
+  ExampleListener * self = EXAMPLE_LISTENER (listener);
+  ExampleHookId hook_id = GUM_IC_GET_FUNC_DATA (ic, ExampleHookId);
+
+  switch (hook_id)
+  {
+    case EXAMPLE_HOOK_OPEN:
+      g_print ("[*] open(\"%s\")\n", (const gchar *) gum_invocation_context_get_nth_argument (ic, 0));
+      break;
+    case EXAMPLE_HOOK_CLOSE:
+      g_print ("[*] close(%d)\n", GPOINTER_TO_INT (gum_invocation_context_get_nth_argument (ic, 0)));
+      break;
+  }
+
+  self->num_calls++;
+}
+
+static void
+example_listener_on_leave (GumInvocationListener * listener,
+                           GumInvocationContext * ic)
+{
+}
+
+static void
+example_listener_class_init (ExampleListenerClass * klass)
+{
+  (void) EXAMPLE_IS_LISTENER;
+  (void) glib_autoptr_cleanup_ExampleListener;
+}
+
+static void
+example_listener_iface_init (gpointer g_iface,
+                             gpointer iface_data)
+{
+  GumInvocationListenerInterface * iface = g_iface;
+
+  iface->on_enter = example_listener_on_enter;
+  iface->on_leave = example_listener_on_leave;
+}
+
+static void
+example_listener_init (ExampleListener * self)
+{
+}
diff --git a/utils/afl_frida/libtestinstr.c b/utils/afl_frida/libtestinstr.c
new file mode 100644
index 00000000..96b1cf21
--- /dev/null
+++ b/utils/afl_frida/libtestinstr.c
@@ -0,0 +1,35 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
diff --git a/utils/afl_network_proxy/GNUmakefile b/utils/afl_network_proxy/GNUmakefile
new file mode 100644
index 00000000..0b55dc2c
--- /dev/null
+++ b/utils/afl_network_proxy/GNUmakefile
@@ -0,0 +1,44 @@
+PREFIX   ?= /usr/local
+BIN_PATH  = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+DOC_PATH  = $(PREFIX)/share/doc/afl
+
+PROGRAMS = afl-network-client afl-network-server
+
+HASH=\#
+
+CFLAGS += -Wno-pointer-sign
+
+ifdef STATIC
+  CFLAGS += -static
+endif
+
+ifeq "$(shell echo '$(HASH)include <libdeflate.h>@int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
+ CFLAGS += -DUSE_DEFLATE=1
+ LDFLAGS += -ldeflate 
+ $(info libdeflate-dev was detected, using compression)
+else
+ $(warn did not find libdeflate-dev, cannot use compression)
+endif
+
+all:	$(PROGRAMS)
+
+help:
+	@echo make options:
+	@echo STATIC - build as static binaries
+	@echo COMPRESS_TESTCASES - compress test cases
+
+afl-network-client:	afl-network-client.c
+	$(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS)
+
+afl-network-server:	afl-network-server.c
+	$(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS)
+
+clean:
+	rm -f $(PROGRAMS) *~ core
+
+install: all
+	install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH)
+	install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH)
+	install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md
+
diff --git a/utils/afl_network_proxy/Makefile b/utils/afl_network_proxy/Makefile
new file mode 100644
index 00000000..0b306dde
--- /dev/null
+++ b/utils/afl_network_proxy/Makefile
@@ -0,0 +1,2 @@
+all:
+	@echo please use GNU make, thanks!
diff --git a/utils/afl_network_proxy/README.md b/utils/afl_network_proxy/README.md
new file mode 100644
index 00000000..a5ac3578
--- /dev/null
+++ b/utils/afl_network_proxy/README.md
@@ -0,0 +1,61 @@
+# afl-network-proxy
+
+If you want to run afl-fuzz over the network than this is what you need :)
+Note that the impact on fuzzing speed will be huge, expect a loss of 90%.
+
+## When to use this
+
+1. when you have to fuzz a target that has to run on a system that cannot
+   contain the fuzzing output (e.g. /tmp too small and file system is read-only)
+2. when the target instantly reboots on crashes
+3. ... any other reason you would need this
+
+## how to get it running
+
+### Compiling
+
+Just type `make` and let the autodetection do everything for you.
+
+Note that you will get a 40-50% performance increase if you have libdeflate-dev
+installed. The GNUmakefile will autodetect it if present.
+
+If your target has large test cases (10+kb) that are ascii only or large chunks
+of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them.
+For most targets this hurts performance though so it is disabled by default.
+
+### on the target
+
+Run `afl-network-server` with your target with the -m and -t values you need.
+Important is the -i parameter which is the TCP port to listen on.
+e.g.:
+```
+afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@
+```
+
+### on the (afl-fuzz) master
+
+Just run afl-fuzz with your normal options, however the target should be
+`afl-network-client` with the IP and PORT of the `afl-network-server` and
+increase the -t value:
+```
+afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111
+```
+Note the '+' on the -t parameter value. The afl-network-server will take
+care of proper timeouts hence afl-fuzz should not. The '+' increases the
+timeout and the value itself should be 500-1000 higher than the one on 
+afl-network-server.
+
+### networking
+
+The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to
+either. Note that also the outgoing interface can be specified with a '%' for
+`afl-network-client`, e.g. `fe80::1234%eth0`.
+
+Also make sure your default TCP window size is larger than your MAP_SIZE
+(130kb is a good value).
+On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem` 
+
+## how to compile and install
+
+`make && sudo make install`
+
diff --git a/utils/afl_network_proxy/afl-network-client.c b/utils/afl_network_proxy/afl-network-client.c
new file mode 100644
index 00000000..a2451fdc
--- /dev/null
+++ b/utils/afl_network_proxy/afl-network-client.c
@@ -0,0 +1,415 @@
+/*
+   american fuzzy lop++ - afl-network-client
+   ---------------------------------------
+
+   Written by Marc Heuse <mh@mh-sec.de>
+
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+*/
+
+#ifdef __ANDROID__
+  #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#ifndef USEMMAP
+  #include <sys/shm.h>
+#endif
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifdef USE_DEFLATE
+  #include <libdeflate.h>
+#endif
+
+u8 *__afl_area_ptr;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+#endif
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+  u32 status;
+  if (!error || error > 0xffff) return;
+  status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+  if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+  char *id_str = getenv(SHM_ENV_VAR);
+  char *ptr;
+
+  if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+    u32 val = atoi(ptr);
+    if (val > 0) __afl_map_size = val;
+
+  }
+
+  if (__afl_map_size > MAP_SIZE) {
+
+    if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
+
+      fprintf(stderr,
+              "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+      if (id_str) {
+
+        send_forkserver_error(FS_ERROR_MAP_SIZE);
+        exit(-1);
+
+      }
+
+    } else {
+
+      fprintf(stderr,
+              "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+
+    }
+
+  }
+
+  if (id_str) {
+
+#ifdef USEMMAP
+    const char *   shm_file_path = id_str;
+    int            shm_fd = -1;
+    unsigned char *shm_base = NULL;
+
+    /* create the shared memory segment as if it was a file */
+    shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+    if (shm_fd == -1) {
+
+      fprintf(stderr, "shm_open() failed\n");
+      send_forkserver_error(FS_ERROR_SHM_OPEN);
+      exit(1);
+
+    }
+
+    /* map the shared memory segment to the address space of the process */
+    shm_base =
+        mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+    if (shm_base == MAP_FAILED) {
+
+      close(shm_fd);
+      shm_fd = -1;
+
+      fprintf(stderr, "mmap() failed\n");
+      send_forkserver_error(FS_ERROR_MMAP);
+      exit(2);
+
+    }
+
+    __afl_area_ptr = shm_base;
+#else
+    u32 shm_id = atoi(id_str);
+
+    __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+    if (__afl_area_ptr == (void *)-1) {
+
+      send_forkserver_error(FS_ERROR_SHMAT);
+      exit(1);
+
+    }
+
+    /* Write something into the bitmap so that the parent doesn't give up */
+
+    __afl_area_ptr[0] = 1;
+
+  }
+
+}
+
+/* Fork server logic. */
+
+static void __afl_start_forkserver(void) {
+
+  u8  tmp[4] = {0, 0, 0, 0};
+  u32 status = 0;
+
+  if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+    status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+  if (status) status |= (FS_OPT_ENABLED);
+  memcpy(tmp, &status, 4);
+
+  /* Phone home and tell the parent that we're OK. */
+
+  if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+}
+
+static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+  s32 status, res = 0x0fffffff;  // res is a dummy pid
+
+  /* Wait for parent by reading from the pipe. Abort if read fails. */
+  if (read(FORKSRV_FD, &status, 4) != 4) return 0;
+
+  /* we have a testcase - read it */
+  status = read(0, buf, max_len);
+
+  /* report that we are starting the target */
+  if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
+
+  if (status < 1)
+    return 0;
+  else
+    return status;
+
+}
+
+static void __afl_end_testcase(int status) {
+
+  if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
+
+}
+
+/* you just need to modify the while() loop in this main() */
+
+int main(int argc, char *argv[]) {
+
+  u8 *            interface, *buf, *ptr;
+  s32             s = -1;
+  struct addrinfo hints, *hres, *aip;
+  u32 *           lenptr, max_len = 65536;
+#ifdef USE_DEFLATE
+  u8 *   buf2;
+  u32 *  lenptr1, *lenptr2, buf2_len, compress_len;
+  size_t decompress_len;
+#endif
+
+  if (argc < 3 || argc > 4) {
+
+    printf("Syntax: %s host port [max-input-size]\n\n", argv[0]);
+    printf("Requires host and port of the remote afl-proxy-server instance.\n");
+    printf(
+        "IPv4 and IPv6 are supported, also binding to an interface with "
+        "\"%%\"\n");
+    printf("The max-input-size default is %u.\n", max_len);
+    printf(
+        "The default map size is %u and can be changed with setting "
+        "AFL_MAP_SIZE.\n",
+        __afl_map_size);
+    exit(-1);
+
+  }
+
+  if ((interface = strchr(argv[1], '%')) != NULL) *interface++ = 0;
+
+  if (argc > 3)
+    if ((max_len = atoi(argv[3])) < 0)
+      FATAL("max-input-size may not be negative or larger than 2GB: %s",
+            argv[3]);
+
+  if ((ptr = getenv("AFL_MAP_SIZE")) != NULL)
+    if ((__afl_map_size = atoi(ptr)) < 8)
+      FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr);
+
+  if ((buf = malloc(max_len + 4)) == NULL)
+    PFATAL("can not allocate %u memory", max_len + 4);
+  lenptr = (u32 *)buf;
+
+#ifdef USE_DEFLATE
+  buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size);
+  if ((buf2 = malloc(buf2_len + 8)) == NULL)
+    PFATAL("can not allocate %u memory", buf2_len + 8);
+  lenptr1 = (u32 *)buf2;
+  lenptr2 = (u32 *)(buf2 + 4);
+#endif
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_family = PF_UNSPEC;
+
+  if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0)
+    PFATAL("could not resolve target %s", argv[1]);
+
+  for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) {
+
+    if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) {
+
+#ifdef SO_BINDTODEVICE
+      if (interface != NULL)
+        if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
+                       strlen(interface) + 1) < 0)
+          fprintf(stderr, "Warning: could not bind to device %s\n", interface);
+#else
+      fprintf(stderr,
+              "Warning: binding to interface is not supported for your OS\n");
+#endif
+
+#ifdef SO_PRIORITY
+      int priority = 7;
+      if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+          0) {
+
+        priority = 6;
+        if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority,
+                       sizeof(priority)) < 0)
+          WARNF("could not set priority on socket");
+
+      }
+
+#endif
+
+      if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1;
+
+    }
+
+  }
+
+#ifdef USE_DEFLATE
+  struct libdeflate_compressor *compressor;
+  compressor = libdeflate_alloc_compressor(1);
+  struct libdeflate_decompressor *decompressor;
+  decompressor = libdeflate_alloc_decompressor();
+  fprintf(stderr, "Compiled with compression support\n");
+#endif
+
+  if (s == -1)
+    FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]);
+  else
+    fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]);
+
+  /* we initialize the shared memory map and start the forkserver */
+  __afl_map_shm();
+  __afl_start_forkserver();
+
+  int i = 1, j, status, ret, received;
+
+  // fprintf(stderr, "Waiting for first testcase\n");
+  while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) {
+
+    // fprintf(stderr, "Sending testcase with len %u\n", *lenptr);
+#ifdef USE_DEFLATE
+  #ifdef COMPRESS_TESTCASES
+    // we only compress the testcase if it does not fit in the TCP packet
+    if (*lenptr > 1500 - 20 - 32 - 4) {
+
+      // set highest byte to signify compression
+      *lenptr1 = (*lenptr | 0xff000000);
+      *lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr,
+                                                  buf2 + 8, buf2_len);
+      if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8)
+        PFATAL("sending test data failed");
+      // fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2);
+      // for (u32 i = 0; i < *lenptr; i++)
+      //  fprintf(stderr, "%02x", buf[i + 4]);
+      // fprintf(stderr, "\n");
+      // for (u32 i = 0; i < *lenptr2; i++)
+      //  fprintf(stderr, "%02x", buf2[i + 8]);
+      // fprintf(stderr, "\n");
+
+    } else {
+
+  #endif
+#endif
+      if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4)
+        PFATAL("sending test data failed");
+#ifdef USE_DEFLATE
+  #ifdef COMPRESS_TESTCASES
+      // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr);
+
+    }
+
+  #endif
+#endif
+
+    received = 0;
+    while (received < 4 &&
+           (ret = recv(s, &status + received, 4 - received, 0)) > 0)
+      received += ret;
+    if (received != 4)
+      FATAL("did not receive waitpid data (%d, %d)", received, ret);
+    // fprintf(stderr, "Received status\n");
+
+    received = 0;
+#ifdef USE_DEFLATE
+    while (received < 4 &&
+           (ret = recv(s, &compress_len + received, 4 - received, 0)) > 0)
+      received += ret;
+    if (received != 4)
+      FATAL("did not receive compress_len (%d, %d)", received, ret);
+    // fprintf(stderr, "Received status\n");
+
+    received = 0;
+    while (received < compress_len &&
+           (ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0)
+      received += ret;
+    if (received != compress_len)
+      FATAL("did not receive coverage data (%d, %d)", received, ret);
+
+    if (libdeflate_deflate_decompress(decompressor, buf2, compress_len,
+                                      __afl_area_ptr, __afl_map_size,
+                                      &decompress_len) != LIBDEFLATE_SUCCESS ||
+        decompress_len != __afl_map_size)
+      FATAL("decompression failed");
+      // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len);
+      // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x",
+      // __afl_area_ptr[i]); fprintf(stderr, "\n");
+#else
+    while (received < __afl_map_size &&
+           (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received,
+                       0)) > 0)
+      received += ret;
+    if (received != __afl_map_size)
+      FATAL("did not receive coverage data (%d, %d)", received, ret);
+#endif
+    // fprintf(stderr, "Received coverage\n");
+
+    /* report the test case is done and wait for the next */
+    __afl_end_testcase(status);
+    // fprintf(stderr, "Waiting for next testcase %d\n", ++i);
+
+  }
+
+#ifdef USE_DEFLATE
+  libdeflate_free_compressor(compressor);
+  libdeflate_free_decompressor(decompressor);
+#endif
+
+  return 0;
+
+}
+
diff --git a/utils/afl_network_proxy/afl-network-server.c b/utils/afl_network_proxy/afl-network-server.c
new file mode 100644
index 00000000..0dfae658
--- /dev/null
+++ b/utils/afl_network_proxy/afl-network-server.c
@@ -0,0 +1,685 @@
+/*
+   american fuzzy lop++ - network proxy server
+   -------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+   Now maintained by Marc Heuse <mh@mh-sec.de>,
+                        Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+                        Andrea Fioraldi <andreafioraldi@gmail.com> and
+                        Dominik Maier <mail@dmnk.co>
+
+   Copyright 2016, 2017 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "forkserver.h"
+#include "sharedmem.h"
+#include "common.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef USE_DEFLATE
+  #include <libdeflate.h>
+struct libdeflate_compressor *  compressor;
+struct libdeflate_decompressor *decompressor;
+#endif
+
+static u8 *in_file,                    /* Minimizer input test case         */
+    *out_file;
+
+static u8 *in_data;                    /* Input data for trimming           */
+static u8 *buf2;
+
+static s32 in_len;
+static s32 buf2_len;
+static u32 map_size = MAP_SIZE;
+
+static volatile u8 stop_soon;          /* Ctrl-C pressed?                   */
+
+/* See if any bytes are set in the bitmap. */
+
+static inline u8 anything_set(afl_forkserver_t *fsrv) {
+
+  u32 *ptr = (u32 *)fsrv->trace_bits;
+  u32  i = (map_size >> 2);
+
+  while (i--) {
+
+    if (*(ptr++)) { return 1; }
+
+  }
+
+  return 0;
+
+}
+
+static void at_exit_handler(void) {
+
+  afl_fsrv_killall();
+
+}
+
+/* Write output file. */
+
+static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
+
+  s32 ret;
+
+  unlink(path);                                            /* Ignore errors */
+
+  ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
+
+  if (ret < 0) { PFATAL("Unable to create '%s'", path); }
+
+  ck_write(ret, mem, len, path);
+
+  lseek(ret, 0, SEEK_SET);
+
+  return ret;
+
+}
+
+/* Execute target application. Returns 0 if the changes are a dud, or
+   1 if they should be kept. */
+
+static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
+                     u8 first_run) {
+
+  afl_fsrv_write_to_testcase(fsrv, mem, len);
+
+  fsrv_run_result_t ret =
+      afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
+
+  if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); }
+
+  if (stop_soon) {
+
+    SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST);
+    exit(1);
+
+  }
+
+  return ret;
+
+}
+
+/* Handle Ctrl-C and the like. */
+
+static void handle_stop_sig(int sig) {
+
+  stop_soon = 1;
+  afl_fsrv_killall();
+
+}
+
+/* Do basic preparations - persistent fds, filenames, etc. */
+
+static void set_up_environment(afl_forkserver_t *fsrv) {
+
+  u8 *x;
+
+  fsrv->dev_null_fd = open("/dev/null", O_RDWR);
+  if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+
+  if (!out_file) {
+
+    u8 *use_dir = ".";
+
+    if (access(use_dir, R_OK | W_OK | X_OK)) {
+
+      use_dir = get_afl_env("TMPDIR");
+      if (!use_dir) { use_dir = "/tmp"; }
+
+    }
+
+    out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid());
+
+  }
+
+  unlink(out_file);
+
+  fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
+
+  if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
+
+  /* Set sane defaults... */
+
+  x = get_afl_env("ASAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "abort_on_error=1")) {
+
+      FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
+
+    }
+
+    if (!strstr(x, "symbolize=0")) {
+
+      FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
+
+    }
+
+  }
+
+  x = get_afl_env("MSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
+
+      FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
+          MSAN_ERROR) " - please fix!");
+
+    }
+
+    if (!strstr(x, "symbolize=0")) {
+
+      FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
+
+    }
+
+  }
+
+  setenv("ASAN_OPTIONS",
+         "abort_on_error=1:"
+         "detect_leaks=0:"
+         "symbolize=0:"
+         "allocator_may_return_null=1",
+         0);
+
+  setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
+                         "symbolize=0:"
+                         "abort_on_error=1:"
+                         "allocator_may_return_null=1:"
+                         "msan_track_origins=0", 0);
+
+  if (get_afl_env("AFL_PRELOAD")) {
+
+    if (fsrv->qemu_mode) {
+
+      /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
+
+    } else {
+
+      setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
+      setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
+
+    }
+
+  }
+
+}
+
+/* Setup signal handlers, duh. */
+
+static void setup_signal_handlers(void) {
+
+  struct sigaction sa;
+
+  sa.sa_handler = NULL;
+  sa.sa_flags = SA_RESTART;
+  sa.sa_sigaction = NULL;
+
+  sigemptyset(&sa.sa_mask);
+
+  /* Various ways of saying "stop". */
+
+  sa.sa_handler = handle_stop_sig;
+  sigaction(SIGHUP, &sa, NULL);
+  sigaction(SIGINT, &sa, NULL);
+  sigaction(SIGTERM, &sa, NULL);
+
+}
+
+/* Display usage hints. */
+
+static void usage(u8 *argv0) {
+
+  SAYF(
+      "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
+
+      "Required parameters:\n"
+
+      "  -i port       - the port to listen for the client to connect to\n\n"
+
+      "Execution control settings:\n"
+
+      "  -f file       - input file read by the tested program (stdin)\n"
+      "  -t msec       - timeout for each run (%d ms)\n"
+      "  -m megs       - memory limit for child process (%d MB)\n"
+      "  -Q            - use binary-only instrumentation (QEMU mode)\n"
+      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
+      "  -W            - use qemu-based instrumentation with Wine (Wine "
+      "mode)\n\n"
+
+      "Environment variables used:\n"
+      "TMPDIR: directory to use for temporary input files\n"
+      "ASAN_OPTIONS: custom settings for ASAN\n"
+      "              (must contain abort_on_error=1 and symbolize=0)\n"
+      "MSAN_OPTIONS: custom settings for MSAN\n"
+      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+      "              the target was compiled for\n"
+      "AFL_PRELOAD:  LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+
+      , argv0, EXEC_TIMEOUT, MEM_LIMIT);
+
+  exit(1);
+
+}
+
+int recv_testcase(int s, void **buf) {
+
+  u32    size;
+  s32    ret;
+  size_t received;
+
+  received = 0;
+  while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0)
+    received += ret;
+  if (received != 4) FATAL("did not receive size information");
+  if (size == 0) FATAL("did not receive valid size information");
+  // fprintf(stderr, "received size information of %d\n", size);
+
+  if ((size & 0xff000000) != 0xff000000) {
+
+    *buf = afl_realloc(buf, size);
+    if (unlikely(!*buf)) { PFATAL("Alloc"); }
+    received = 0;
+    // fprintf(stderr, "unCOMPRESS (%u)\n", size);
+    while (received < size &&
+           (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0)
+      received += ret;
+
+  } else {
+
+#ifdef USE_DEFLATE
+    u32 clen;
+    size -= 0xff000000;
+    *buf = afl_realloc(buf, size);
+    if (unlikely(!*buf)) { PFATAL("Alloc"); }
+    received = 0;
+    while (received < 4 &&
+           (ret = recv(s, &clen + received, 4 - received, 0)) > 0)
+      received += ret;
+    if (received != 4) FATAL("did not receive clen1 information");
+    // fprintf(stderr, "received clen information of %d\n", clen);
+    if (clen < 1)
+      FATAL("did not receive valid compressed len information: %u", clen);
+    buf2 = afl_realloc((void **)&buf2, clen);
+    buf2_len = clen;
+    if (unlikely(!buf2)) { PFATAL("Alloc"); }
+    received = 0;
+    while (received < clen &&
+           (ret = recv(s, buf2 + received, clen - received, 0)) > 0)
+      received += ret;
+    if (received != clen) FATAL("did not receive compressed information");
+    if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf,
+                                      size, &received) != LIBDEFLATE_SUCCESS)
+      FATAL("decompression failed");
+      // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received);
+      // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]);
+      // fprintf(stderr, "\n");
+      // for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x",
+      // ((u8*)(*buf))[i]); fprintf(stderr, "\n");
+#else
+    FATAL("Received compressed data but not compiled with compression support");
+#endif
+
+  }
+
+  // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len);
+  if (received != size)
+    FATAL("did not receive testcase data %lu != %u, %d", received, size, ret);
+  // fprintf(stderr, "received testcase\n");
+  return size;
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv_orig, char **envp) {
+
+  s32    opt, s, sock, on = 1, port = -1;
+  u8     mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+  char **use_argv;
+  struct sockaddr_in6 serveraddr, clientaddr;
+  int                 addrlen = sizeof(clientaddr);
+  char                str[INET6_ADDRSTRLEN];
+  char **             argv = argv_cpy_dup(argc, argv_orig);
+  u8 *                send_buf;
+#ifdef USE_DEFLATE
+  u32 *lenptr;
+#endif
+
+  afl_forkserver_t  fsrv_var = {0};
+  afl_forkserver_t *fsrv = &fsrv_var;
+  afl_fsrv_init(fsrv);
+  map_size = get_map_size();
+  fsrv->map_size = map_size;
+
+  if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc");
+
+  while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) {
+
+    switch (opt) {
+
+      case 'i':
+
+        if (port > 0) { FATAL("Multiple -i options not supported"); }
+        port = atoi(optarg);
+        if (port < 1 || port > 65535)
+          FATAL("invalid port definition, must be between 1-65535: %s", optarg);
+        break;
+
+      case 'f':
+
+        if (out_file) { FATAL("Multiple -f options not supported"); }
+        fsrv->use_stdin = 0;
+        out_file = optarg;
+        break;
+
+      case 'm': {
+
+        u8 suffix = 'M';
+
+        if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
+        mem_limit_given = 1;
+
+        if (!optarg) { FATAL("Wrong usage of -m"); }
+
+        if (!strcmp(optarg, "none")) {
+
+          fsrv->mem_limit = 0;
+          break;
+
+        }
+
+        if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
+            optarg[0] == '-') {
+
+          FATAL("Bad syntax used for -m");
+
+        }
+
+        switch (suffix) {
+
+          case 'T':
+            fsrv->mem_limit *= 1024 * 1024;
+            break;
+          case 'G':
+            fsrv->mem_limit *= 1024;
+            break;
+          case 'k':
+            fsrv->mem_limit /= 1024;
+            break;
+          case 'M':
+            break;
+
+          default:
+            FATAL("Unsupported suffix or bad syntax for -m");
+
+        }
+
+        if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+
+        if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
+
+          FATAL("Value of -m out of range on 32-bit systems");
+
+        }
+
+      }
+
+      break;
+
+      case 't':
+
+        if (timeout_given) { FATAL("Multiple -t options not supported"); }
+        timeout_given = 1;
+
+        if (!optarg) { FATAL("Wrong usage of -t"); }
+
+        fsrv->exec_tmout = atoi(optarg);
+
+        if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
+
+          FATAL("Dangerously low value of -t");
+
+        }
+
+        break;
+
+      case 'Q':
+
+        if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
+        if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
+
+        fsrv->qemu_mode = 1;
+        break;
+
+      case 'U':
+
+        if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
+        if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
+
+        unicorn_mode = 1;
+        break;
+
+      case 'W':                                           /* Wine+QEMU mode */
+
+        if (use_wine) { FATAL("Multiple -W options not supported"); }
+        fsrv->qemu_mode = 1;
+        use_wine = 1;
+
+        if (!mem_limit_given) { fsrv->mem_limit = 0; }
+
+        break;
+
+      case 'h':
+        usage(argv[0]);
+        return -1;
+        break;
+
+      default:
+        usage(argv[0]);
+
+    }
+
+  }
+
+  if (optind == argc || port < 1) { usage(argv[0]); }
+
+  check_environment_vars(envp);
+
+  sharedmem_t shm = {0};
+  fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
+
+  in_data = afl_realloc((void **)&in_data, 65536);
+  if (unlikely(!in_data)) { PFATAL("Alloc"); }
+
+  atexit(at_exit_handler);
+  setup_signal_handlers();
+
+  set_up_environment(fsrv);
+
+  fsrv->target_path = find_binary(argv[optind]);
+  detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
+
+  if (fsrv->qemu_mode) {
+
+    if (use_wine) {
+
+      use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
+                               argv + optind);
+
+    } else {
+
+      use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
+                               argv + optind);
+
+    }
+
+  } else {
+
+    use_argv = argv + optind;
+
+  }
+
+  if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed");
+
+#ifdef SO_REUSEADDR
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
+
+    WARNF("setsockopt(SO_REUSEADDR) failed");
+
+  }
+
+#endif
+
+#ifdef SO_PRIORITY
+  int priority = 7;
+  if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+      0) {
+
+    priority = 6;
+    if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) <
+        0)
+      WARNF("could not set priority on socket");
+
+  }
+
+#endif
+
+  memset(&serveraddr, 0, sizeof(serveraddr));
+  serveraddr.sin6_family = AF_INET6;
+  serveraddr.sin6_port = htons(port);
+  serveraddr.sin6_addr = in6addr_any;
+
+  if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
+    PFATAL("bind() failed");
+
+  if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
+
+  afl_fsrv_start(
+      fsrv, use_argv, &stop_soon,
+      (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+          ? 1
+          : 0);
+
+#ifdef USE_DEFLATE
+  compressor = libdeflate_alloc_compressor(1);
+  decompressor = libdeflate_alloc_decompressor();
+  buf2 = afl_realloc((void **)&buf2, map_size + 16);
+  buf2_len = map_size + 16;
+  if (unlikely(!buf2)) { PFATAL("alloc"); }
+  lenptr = (u32 *)(buf2 + 4);
+  fprintf(stderr, "Compiled with compression support\n");
+#endif
+
+  fprintf(stderr,
+          "Waiting for incoming connection from afl-network-client on port %d "
+          "...\n",
+          port);
+
+  if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); }
+  fprintf(stderr, "Received connection, starting ...\n");
+
+#ifdef SO_PRIORITY
+  priority = 7;
+  if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) {
+
+    priority = 6;
+    if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
+      WARNF("could not set priority on socket");
+
+  }
+
+#endif
+
+  while ((in_len = recv_testcase(s, (void **)&in_data)) > 0) {
+
+    // fprintf(stderr, "received %u\n", in_len);
+    (void)run_target(fsrv, use_argv, in_data, in_len, 1);
+
+    memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size);
+
+#ifdef USE_DEFLATE
+    memcpy(buf2, &fsrv->child_status, 4);
+    *lenptr = (u32)libdeflate_deflate_compress(
+        compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8);
+    // fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr);
+    // for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x",
+    // fsrv->trace_bits[i]); fprintf(stderr, "\n");
+    if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr)
+      FATAL("could not send data");
+#else
+    memcpy(send_buf, &fsrv->child_status, 4);
+    if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size)
+      FATAL("could not send data");
+#endif
+
+    // fprintf(stderr, "sent result\n");
+
+  }
+
+  unlink(out_file);
+  if (out_file) { ck_free(out_file); }
+  out_file = NULL;
+
+  afl_shm_deinit(&shm);
+  afl_fsrv_deinit(fsrv);
+  if (fsrv->target_path) { ck_free(fsrv->target_path); }
+  afl_free(in_data);
+#if USE_DEFLATE
+  afl_free(buf2);
+  libdeflate_free_compressor(compressor);
+  libdeflate_free_decompressor(decompressor);
+#endif
+
+  argv_cpy_free(argv);
+
+  exit(0);
+
+}
+
diff --git a/utils/afl_proxy/Makefile b/utils/afl_proxy/Makefile
new file mode 100644
index 00000000..4b368f8d
--- /dev/null
+++ b/utils/afl_proxy/Makefile
@@ -0,0 +1,7 @@
+all:	afl-proxy
+
+afl-proxy:	afl-proxy.c
+	$(CC) -I../../include -o afl-proxy afl-proxy.c
+
+clean:
+	rm -f afl-proxy *~ core
diff --git a/utils/afl_proxy/README.md b/utils/afl_proxy/README.md
new file mode 100644
index 00000000..3c768a19
--- /dev/null
+++ b/utils/afl_proxy/README.md
@@ -0,0 +1,9 @@
+# afl-proxy
+
+afl-proxy is an example skeleton file which can easily be used to fuzz
+and instrument non-standard things.
+
+You only need to change the while() loop of the main() to send the
+data of buf[] with length len to the target and write the coverage
+information to __afl_area_ptr[__afl_map_size]
+
diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c
new file mode 100644
index 00000000..aa7a361a
--- /dev/null
+++ b/utils/afl_proxy/afl-proxy.c
@@ -0,0 +1,238 @@
+/*
+   american fuzzy lop++ - afl-proxy skeleton example
+   ---------------------------------------------------
+
+   Written by Marc Heuse <mh@mh-sec.de>
+
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+
+   HOW-TO
+   ======
+
+   You only need to change the while() loop of the main() to send the
+   data of buf[] with length len to the target and write the coverage
+   information to __afl_area_ptr[__afl_map_size]
+
+
+*/
+
+#ifdef __ANDROID__
+  #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+u8 *__afl_area_ptr;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+#endif
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+  u32 status;
+  if (!error || error > 0xffff) return;
+  status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+  if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+  char *id_str = getenv(SHM_ENV_VAR);
+  char *ptr;
+
+  if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+    u32 val = atoi(ptr);
+    if (val > 0) __afl_map_size = val;
+
+  }
+
+  if (__afl_map_size > MAP_SIZE) {
+
+    if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
+
+      fprintf(stderr,
+              "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+      if (id_str) {
+
+        send_forkserver_error(FS_ERROR_MAP_SIZE);
+        exit(-1);
+
+      }
+
+    } else {
+
+      fprintf(stderr,
+              "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+
+    }
+
+  }
+
+  if (id_str) {
+
+#ifdef USEMMAP
+    const char *   shm_file_path = id_str;
+    int            shm_fd = -1;
+    unsigned char *shm_base = NULL;
+
+    /* create the shared memory segment as if it was a file */
+    shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+    if (shm_fd == -1) {
+
+      fprintf(stderr, "shm_open() failed\n");
+      send_forkserver_error(FS_ERROR_SHM_OPEN);
+      exit(1);
+
+    }
+
+    /* map the shared memory segment to the address space of the process */
+    shm_base =
+        mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+    if (shm_base == MAP_FAILED) {
+
+      close(shm_fd);
+      shm_fd = -1;
+
+      fprintf(stderr, "mmap() failed\n");
+      send_forkserver_error(FS_ERROR_MMAP);
+      exit(2);
+
+    }
+
+    __afl_area_ptr = shm_base;
+#else
+    u32 shm_id = atoi(id_str);
+
+    __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+    if (__afl_area_ptr == (void *)-1) {
+
+      send_forkserver_error(FS_ERROR_SHMAT);
+      exit(1);
+
+    }
+
+    /* Write something into the bitmap so that the parent doesn't give up */
+
+    __afl_area_ptr[0] = 1;
+
+  }
+
+}
+
+/* Fork server logic. */
+
+static void __afl_start_forkserver(void) {
+
+  u8  tmp[4] = {0, 0, 0, 0};
+  u32 status = 0;
+
+  if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+    status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+  if (status) status |= (FS_OPT_ENABLED);
+  memcpy(tmp, &status, 4);
+
+  /* Phone home and tell the parent that we're OK. */
+
+  if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+}
+
+static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+  s32 status, res = 0xffffff;
+
+  /* Wait for parent by reading from the pipe. Abort if read fails. */
+  if (read(FORKSRV_FD, &status, 4) != 4) return 0;
+
+  /* we have a testcase - read it */
+  status = read(0, buf, max_len);
+
+  /* report that we are starting the target */
+  if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
+
+  if (status < 1)
+    return 0;
+  else
+    return status;
+
+}
+
+static void __afl_end_testcase(void) {
+
+  int status = 0xffffff;
+
+  if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
+
+}
+
+/* you just need to modify the while() loop in this main() */
+
+int main(int argc, char *argv[]) {
+
+  /* This is were the testcase data is written into */
+  u8  buf[1024];  // this is the maximum size for a test case! set it!
+  u32 len;
+
+  /* here you specify the map size you need that you are reporting to
+     afl-fuzz.  Any value is fine as long as it can be divided by 32. */
+  __afl_map_size = MAP_SIZE;  // default is 65536
+
+  /* then we initialize the shared memory map and start the forkserver */
+  __afl_map_shm();
+  __afl_start_forkserver();
+
+  while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
+
+    /* here you have to create the magic that feeds the buf/len to the
+       target and write the coverage to __afl_area_ptr */
+
+    // ... the magic ...
+
+    /* report the test case is done and wait for the next */
+    __afl_end_testcase();
+
+  }
+
+  return 0;
+
+}
+
diff --git a/utils/afl_untracer/Makefile b/utils/afl_untracer/Makefile
new file mode 100644
index 00000000..14a09b41
--- /dev/null
+++ b/utils/afl_untracer/Makefile
@@ -0,0 +1,16 @@
+ifdef DEBUG
+  OPT=-O0
+else
+  OPT=-O3
+endif
+
+all:	afl-untracer libtestinstr.so
+
+afl-untracer:	afl-untracer.c
+	$(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl
+
+libtestinstr.so:	libtestinstr.c
+	$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
+
+clean:
+	rm -f afl-untracer libtestinstr.so *~ core
diff --git a/utils/afl_untracer/README.md b/utils/afl_untracer/README.md
new file mode 100644
index 00000000..ada0c916
--- /dev/null
+++ b/utils/afl_untracer/README.md
@@ -0,0 +1,60 @@
+# afl-untracer - fast fuzzing of binary-only libraries
+
+## Introduction
+
+afl-untracer is an example skeleton file which can easily be used to fuzz
+a closed source library.
+
+It requires less memory and is x3-5 faster than qemu_mode however it is way
+more course grained and does not provide interesting features like compcov
+or cmplog.
+
+Supported is so far Intel (i386/x86_64) and AARCH64.
+
+## How-to
+
+### Modify afl-untracer.c
+
+Read and modify afl-untracer.c then `make`.
+To adapt afl-untracer.c to your needs, read the header of the file and then
+search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
+
+### Generate patches.txt file
+
+To generate the `patches.txt` file for your target library use the
+`ida_get_patchpoints.py` script for IDA Pro or
+`ghidra_get_patchpoints.java` for Ghidra.
+
+The patches.txt file has to be pointed to by `AFL_UNTRACER_FILE`.
+
+To easily run the scripts without needing to run the GUI with Ghidra:
+```
+/opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
+rm -rf /tmp/tmp$$
+```
+The file is created at `~/Desktop/patches.txt`
+
+### Fuzzing
+
+Example (after modifying afl-untracer.c to your needs, compiling and creating
+patches.txt):
+```
+LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
+```
+(or even remote via afl-network-proxy).
+
+### Testing and debugging
+
+For testing/debugging you can try:
+```
+make DEBUG=1
+AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer
+```
+and then you can easily set breakpoints to "breakpoint" and "fuzz".
+
+# Background
+
+This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
+and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
+This implementation is slower because the traps are not patched out with each
+run, but on the other hand gives much better coverage information.
diff --git a/utils/afl_untracer/TODO b/utils/afl_untracer/TODO
new file mode 100644
index 00000000..fffffacf
--- /dev/null
+++ b/utils/afl_untracer/TODO
@@ -0,0 +1,2 @@
+ * add shmem fuzzing
+ * add snapshot feature?
diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c
new file mode 100644
index 00000000..2baeb58d
--- /dev/null
+++ b/utils/afl_untracer/afl-untracer.c
@@ -0,0 +1,777 @@
+/*
+   american fuzzy lop++ - afl-untracer skeleton example
+   ---------------------------------------------------
+
+   Written by Marc Heuse <mh@mh-sec.de>
+
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+
+   HOW-TO
+   ======
+
+   You only need to change the following:
+
+   1. decide if you want to receive data from stdin [DEFAULT] or file(name)
+      -> use_stdin = 0 if via file, and what the maximum input size is
+   2. dl load the library you want to fuzz, lookup the functions you need
+      and setup the calls to these
+   3. in the while loop you call the functions in the necessary order -
+      incl the cleanup. the cleanup is important!
+
+   Just look these steps up in the code, look for "// STEP x:"
+
+
+*/
+
+#define __USE_GNU
+#define _GNU_SOURCE
+
+#ifdef __ANDROID__
+  #include "android-ashmem.h"
+#endif
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#if defined(__linux__)
+  #include <sys/personality.h>
+  #include <sys/ucontext.h>
+#elif defined(__APPLE__) && defined(__LP64__)
+  #include <mach-o/dyld_images.h>
+#elif defined(__FreeBSD__)
+  #include <sys/sysctl.h>
+  #include <sys/user.h>
+#else
+  #error "Unsupported platform"
+#endif
+
+#define MEMORY_MAP_DECREMENT 0x200000000000
+#define MAX_LIB_COUNT 128
+
+// STEP 1:
+
+/* here you need to specify the parameter for the target function */
+static void *(*o_function)(u8 *buf, int len);
+
+/* use stdin (1) or a file on the commandline (0) */
+static u32 use_stdin = 1;
+
+/* This is were the testcase data is written into */
+static u8 buf[10000];  // this is the maximum size for a test case! set it!
+
+/* If you want to have debug output set this to 1, can also be set with
+   AFL_DEBUG  */
+static u32 debug = 0;
+
+// END STEP 1
+
+typedef struct library_list {
+
+  u8 *name;
+  u64 addr_start, addr_end;
+
+} library_list_t;
+
+#ifdef __ANDROID__
+u32 __afl_map_size = MAP_SIZE;
+u32 do_exit;
+#else
+__thread u32 __afl_map_size = MAP_SIZE;
+__thread u32 do_exit;
+#endif
+
+static pid_t     pid = 65537;
+static pthread_t __afl_thread;
+static u8        __afl_dummy[MAP_SIZE];
+static u8 *      __afl_area_ptr = __afl_dummy;
+static u8 *      inputfile;  // this will point to argv[1]
+static u32       len;
+
+static library_list_t liblist[MAX_LIB_COUNT];
+static u32            liblist_cnt;
+
+static void sigtrap_handler(int signum, siginfo_t *si, void *context);
+static void fuzz(void);
+
+/* read the library information */
+void read_library_information(void) {
+
+#if defined(__linux__)
+  FILE *f;
+  u8    buf[1024], *b, *m, *e, *n;
+
+  if ((f = fopen("/proc/self/maps", "r")) == NULL)
+    FATAL("cannot open /proc/self/maps");
+
+  if (debug) fprintf(stderr, "Library list:\n");
+  while (fgets(buf, sizeof(buf), f)) {
+
+    if (strstr(buf, " r-x")) {
+
+      if (liblist_cnt >= MAX_LIB_COUNT) {
+
+        WARNF("too many libraries to old, maximum count of %d reached",
+              liblist_cnt);
+        return;
+
+      }
+
+      b = buf;
+      m = index(buf, '-');
+      e = index(buf, ' ');
+      if ((n = strrchr(buf, '/')) == NULL) n = strrchr(buf, ' ');
+      if (n &&
+          ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
+        n = NULL;
+      else
+        n++;
+      if (b && m && e && n && *n) {
+
+        *m++ = 0;
+        *e = 0;
+        if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
+
+        liblist[liblist_cnt].name = strdup(n);
+        liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
+        liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
+        if (debug)
+          fprintf(
+              stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
+              liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+              liblist[liblist_cnt].addr_start,
+              liblist[liblist_cnt].addr_end - 1);
+        liblist_cnt++;
+
+      }
+
+    }
+
+  }
+
+  if (debug) fprintf(stderr, "\n");
+
+#elif defined(__FreeBSD__)
+  int    mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
+  char * buf, *start, *end;
+  size_t miblen = sizeof(mib) / sizeof(mib[0]);
+  size_t len;
+
+  if (debug) fprintf(stderr, "Library list:\n");
+  if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
+
+  len = len * 4 / 3;
+
+  buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+  if (buf == MAP_FAILED) { return; }
+
+  if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
+
+    munmap(buf, len);
+    return;
+
+  }
+
+  start = buf;
+  end = buf + len;
+
+  while (start < end) {
+
+    struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
+    size_t                size = region->kve_structsize;
+
+    if (size == 0) { break; }
+
+    if ((region->kve_protection & KVME_PROT_READ) &&
+        !(region->kve_protection & KVME_PROT_EXEC)) {
+
+      liblist[liblist_cnt].name =
+          region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
+      liblist[liblist_cnt].addr_start = region->kve_start;
+      liblist[liblist_cnt].addr_end = region->kve_end;
+
+      if (debug) {
+
+        fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
+                liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+                liblist[liblist_cnt].addr_start,
+                liblist[liblist_cnt].addr_end - 1);
+
+      }
+
+      liblist_cnt++;
+
+    }
+
+    start += size;
+
+  }
+
+#endif
+
+}
+
+library_list_t *find_library(char *name) {
+
+#if defined(__linux__)
+  u32 i;
+
+  for (i = 0; i < liblist_cnt; i++)
+    if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i];
+#elif defined(__APPLE__) && defined(__LP64__)
+  kern_return_t         err;
+  static library_list_t lib;
+
+  // get the list of all loaded modules from dyld
+  // the task_info mach API will get the address of the dyld all_image_info
+  // struct for the given task from which we can get the names and load
+  // addresses of all modules
+  task_dyld_info_data_t  task_dyld_info;
+  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+  err = task_info(mach_task_self(), TASK_DYLD_INFO,
+                  (task_info_t)&task_dyld_info, &count);
+
+  const struct dyld_all_image_infos *all_image_infos =
+      (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
+  const struct dyld_image_info *image_infos = all_image_infos->infoArray;
+
+  for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
+
+    const char *      image_name = image_infos[i].imageFilePath;
+    mach_vm_address_t image_load_address =
+        (mach_vm_address_t)image_infos[i].imageLoadAddress;
+    if (strstr(image_name, name)) {
+
+      lib.name = name;
+      lib.addr_start = (u64)image_load_address;
+      lib.addr_end = 0;
+      return &lib;
+
+    }
+
+  }
+
+#endif
+
+  return NULL;
+
+}
+
+/* for having an easy breakpoint location after loading the shared library */
+// this seems to work for clang too. nice :) requires gcc 4.4+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+void        breakpoint(void) {
+
+  if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n");
+
+}
+
+#pragma GCC pop_options
+
+/* Error reporting to forkserver controller */
+
+void send_forkserver_error(int error) {
+
+  u32 status;
+  if (!error || error > 0xffff) return;
+  status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
+  if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
+
+}
+
+/* SHM setup. */
+
+static void __afl_map_shm(void) {
+
+  char *id_str = getenv(SHM_ENV_VAR);
+  char *ptr;
+
+  if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
+
+    u32 val = atoi(ptr);
+    if (val > 0) __afl_map_size = val;
+
+  }
+
+  if (__afl_map_size > MAP_SIZE) {
+
+    if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
+
+      fprintf(stderr,
+              "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+      if (id_str) {
+
+        send_forkserver_error(FS_ERROR_MAP_SIZE);
+        exit(-1);
+
+      }
+
+    } else {
+
+      fprintf(stderr,
+              "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
+              "be able to run this instrumented program!\n",
+              __afl_map_size);
+
+    }
+
+  }
+
+  if (id_str) {
+
+#ifdef USEMMAP
+    const char *   shm_file_path = id_str;
+    int            shm_fd = -1;
+    unsigned char *shm_base = NULL;
+
+    /* create the shared memory segment as if it was a file */
+    shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+    if (shm_fd == -1) {
+
+      fprintf(stderr, "shm_open() failed\n");
+      send_forkserver_error(FS_ERROR_SHM_OPEN);
+      exit(1);
+
+    }
+
+    /* map the shared memory segment to the address space of the process */
+    shm_base =
+        mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+
+    if (shm_base == MAP_FAILED) {
+
+      close(shm_fd);
+      shm_fd = -1;
+
+      fprintf(stderr, "mmap() failed\n");
+      send_forkserver_error(FS_ERROR_MMAP);
+      exit(2);
+
+    }
+
+    __afl_area_ptr = shm_base;
+#else
+    u32 shm_id = atoi(id_str);
+
+    __afl_area_ptr = shmat(shm_id, 0, 0);
+
+#endif
+
+    if (__afl_area_ptr == (void *)-1) {
+
+      send_forkserver_error(FS_ERROR_SHMAT);
+      exit(1);
+
+    }
+
+    /* Write something into the bitmap so that the parent doesn't give up */
+
+    __afl_area_ptr[0] = 1;
+
+  }
+
+}
+
+/* Fork server logic. */
+inline static void __afl_start_forkserver(void) {
+
+  u8  tmp[4] = {0, 0, 0, 0};
+  u32 status = 0;
+
+  if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
+    status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
+  if (status) status |= (FS_OPT_ENABLED);
+  memcpy(tmp, &status, 4);
+
+  /* Phone home and tell the parent that we're OK. */
+  if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1;
+  // fprintf(stderr, "write0 %d\n", do_exit);
+
+}
+
+inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+
+  s32 status;
+
+  /* Wait for parent by reading from the pipe. Abort if read fails. */
+  if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1;
+  // fprintf(stderr, "read %d\n", do_exit);
+
+  /* we have a testcase - read it if we read from stdin */
+  if (use_stdin) {
+
+    if ((status = read(0, buf, max_len)) <= 0) exit(-1);
+
+  } else
+
+    status = 1;
+  // fprintf(stderr, "stdin: %d %d\n", use_stdin, status);
+
+  /* report that we are starting the target */
+  if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1;
+  // fprintf(stderr, "write1 %d\n", do_exit);
+
+  __afl_area_ptr[0] = 1;  // put something in the map
+
+  return status;
+
+}
+
+inline static void __afl_end_testcase(int status) {
+
+  if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
+  // fprintf(stderr, "write2 %d\n", do_exit);
+  if (do_exit) exit(0);
+
+}
+
+#ifdef __aarch64__
+  #define SHADOW(addr)                                     \
+    ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \
+                  MEMORY_MAP_DECREMENT -                   \
+                  ((uintptr_t)addr & 0x7) * 0x10000000000))
+#else
+  #define SHADOW(addr)                                     \
+    ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \
+                  MEMORY_MAP_DECREMENT -                   \
+                  ((uintptr_t)addr & 0x3) * 0x10000000000))
+#endif
+
+void setup_trap_instrumentation(void) {
+
+  library_list_t *lib_base = NULL;
+  size_t          lib_size = 0;
+  u8 *            lib_addr;
+  char *          line = NULL;
+  size_t          nread, len = 0;
+  char *          filename = getenv("AFL_UNTRACER_FILE");
+  if (!filename) filename = getenv("TRAPFUZZ_FILE");
+  if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set");
+
+  FILE *patches = fopen(filename, "r");
+  if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename);
+
+    // Index into the coverage bitmap for the current trap instruction.
+#ifdef __aarch64__
+  uint64_t bitmap_index = 0;
+  #ifdef __APPLE__
+  pthread_jit_write_protect_np(0);
+  #endif
+#else
+  uint32_t bitmap_index = 0;
+#endif
+
+  while ((nread = getline(&line, &len, patches)) != -1) {
+
+    char *end = line + len;
+
+    char *col = strchr(line, ':');
+    if (col) {
+
+      // It's a library:size pair
+      *col++ = 0;
+
+      lib_base = find_library(line);
+      if (!lib_base) FATAL("Library %s does not appear to be loaded", line);
+
+      // we ignore the defined lib_size
+      lib_size = strtoul(col, NULL, 16);
+#if (__linux__)
+      if (lib_size < lib_base->addr_end - lib_base->addr_start)
+        lib_size = lib_base->addr_end - lib_base->addr_start;
+#endif
+      if (lib_size % 0x1000 != 0)
+        WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000",
+              lib_size);
+
+      lib_addr = (u8 *)lib_base->addr_start;
+      // Make library code writable.
+      if (mprotect((void *)lib_addr, lib_size,
+                   PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+        FATAL("Failed to mprotect library %s writable", line);
+
+        // Create shadow memory.
+#ifdef __aarch64__
+      for (int i = 0; i < 8; i++) {
+
+#else
+      for (int i = 0; i < 4; i++) {
+
+#endif
+
+        void *shadow_addr = SHADOW(lib_addr + i);
+        void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE,
+                            MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
+        if (debug)
+          fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow,
+                  shadow + lib_size - 1, lib_addr);
+        if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory");
+
+      }
+
+      // Done, continue with next line.
+      continue;
+
+    }
+
+    // It's an offset, parse it and do the patching.
+    unsigned long offset = strtoul(line, NULL, 16);
+
+    if (offset > lib_size)
+      FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
+            offset, lib_size);
+
+    if (bitmap_index >= __afl_map_size)
+      FATAL("Too many basic blocks to instrument");
+
+#ifdef __arch64__
+    uint64_t
+#else
+    uint32_t
+#endif
+        *shadow = SHADOW(lib_addr + offset);
+    if (*shadow != 0) continue;  // skip duplicates
+
+      // Make lookup entry in shadow memory.
+
+#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \
+     defined(__i386__))
+
+    // this is for Intel x64
+
+    uint8_t orig_byte = lib_addr[offset];
+    *shadow = (bitmap_index << 8) | orig_byte;
+    lib_addr[offset] = 0xcc;  // replace instruction with debug trap
+    if (debug)
+      fprintf(stderr,
+              "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %08x\n",
+              lib_addr, offset, lib_addr + offset, orig_byte, shadow,
+              bitmap_index, *shadow);
+
+#elif defined(__aarch64__)
+
+    // this is for aarch64
+
+    uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset);
+    uint32_t  orig_bytes = *patch_bytes;
+    *shadow = (bitmap_index << 32) | orig_bytes;
+    *patch_bytes = 0xd4200000;  // replace instruction with debug trap
+    if (debug)
+      fprintf(stderr,
+              "Patch entry: %p[%lx] = %p = %02x -> SHADOW(%p) #%d -> %016x\n",
+              lib_addr, offset, lib_addr + offset, orig_bytes, shadow,
+              bitmap_index, *shadow);
+
+#else
+    // this will be ARM and AARCH64
+    // for ARM we will need to identify if the code is in thumb or ARM
+  #error "non x86_64/aarch64 not supported yet"
+    //__arm__:
+    // linux thumb: 0xde01
+    // linux arm: 0xe7f001f0
+    //__aarch64__:
+    // linux aarch64: 0xd4200000
+#endif
+
+    bitmap_index++;
+
+  }
+
+  free(line);
+  fclose(patches);
+
+  // Install signal handler for SIGTRAP.
+  struct sigaction s;
+  s.sa_flags = SA_SIGINFO;
+  s.sa_sigaction = sigtrap_handler;
+  sigemptyset(&s.sa_mask);
+  sigaction(SIGTRAP, &s, 0);
+
+  if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index);
+  __afl_map_size = bitmap_index;
+  if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3);
+
+}
+
+/* the signal handler for the traps / debugging interrupts
+   No debug output here because this would cost speed      */
+static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
+
+  uint64_t addr;
+  // Must re-execute the instruction, so decrement PC by one instruction.
+  ucontext_t *ctx = (ucontext_t *)context;
+#if defined(__APPLE__) && defined(__LP64__)
+  #if defined(__x86_64__)
+  ctx->uc_mcontext->__ss.__rip -= 1;
+  addr = ctx->uc_mcontext->__ss.__rip;
+  #else
+  ctx->uc_mcontext->__ss.__pc -= 4;
+  addr = ctx->uc_mcontext->__ss.__pc;
+  #endif
+#elif defined(__linux__)
+  #if defined(__x86_64__) || defined(__i386__)
+  ctx->uc_mcontext.gregs[REG_RIP] -= 1;
+  addr = ctx->uc_mcontext.gregs[REG_RIP];
+  #elif defined(__aarch64__)
+  ctx->uc_mcontext.pc -= 4;
+  addr = ctx->uc_mcontext.pc;
+  #else
+    #error "Unsupported processor"
+  #endif
+#elif defined(__FreeBSD__) && defined(__LP64__)
+  ctx->uc_mcontext.mc_rip -= 1;
+  addr = ctx->uc_mcontext.mc_rip;
+#else
+  #error "Unsupported platform"
+#endif
+
+  // fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr,
+  // si->si_addr);
+
+  // If the trap didn't come from our instrumentation, then we probably will
+  // just segfault here
+  uint8_t *faultaddr;
+  if (unlikely(si->si_addr))
+    faultaddr = (u8 *)si->si_addr - 1;
+  else
+    faultaddr = (u8 *)addr;
+  // if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr));
+  uint32_t shadow = *SHADOW(faultaddr);
+  uint8_t  orig_byte = shadow & 0xff;
+  uint32_t index = shadow >> 8;
+
+  // if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n",
+  // shadow, orig_byte, index);
+
+  // Index zero is invalid so that it is still possible to catch actual trap
+  // instructions in instrumented libraries.
+  if (unlikely(index == 0)) abort();
+
+  // Restore original instruction
+  *faultaddr = orig_byte;
+
+  __afl_area_ptr[index] = 128;
+
+}
+
+/* the MAIN function */
+int main(int argc, char *argv[]) {
+
+#if defined(__linux__)
+  (void)personality(ADDR_NO_RANDOMIZE);  // disable ASLR
+#endif
+
+  pid = getpid();
+  if (getenv("AFL_DEBUG")) debug = 1;
+
+  /* by default we use stdin, but also a filename can be passed, in this
+     case the input is argv[1] and we have to disable stdin */
+  if (argc > 1) {
+
+    use_stdin = 0;
+    inputfile = argv[1];
+
+  }
+
+  // STEP 2: load the library you want to fuzz and lookup the functions,
+  //         inclusive of the cleanup functions
+  //         NOTE: above the main() you have to define the functions!
+
+  void *dl = dlopen("./libtestinstr.so", RTLD_LAZY);
+  if (!dl) FATAL("could not find target library");
+  o_function = dlsym(dl, "testinstr");
+  if (!o_function) FATAL("could not resolve target function from library");
+  if (debug) fprintf(stderr, "Function address: %p\n", o_function);
+
+  // END STEP 2
+
+  /* setup instrumentation, shared memory and forkserver */
+  breakpoint();
+  read_library_information();
+  setup_trap_instrumentation();
+  __afl_map_shm();
+  __afl_start_forkserver();
+
+  while (1) {
+
+    // instead of fork() we could also use the snapshot lkm or do our own mini
+    // snapshot feature like in https://github.com/marcinguy/fuzzer
+    // -> snapshot.c
+    if ((pid = fork()) == -1) PFATAL("fork failed");
+
+    if (pid) {
+
+      u32 status;
+      if (waitpid(pid, &status, 0) < 0) exit(1);
+      /* report the test case is done and wait for the next */
+      __afl_end_testcase(status);
+
+    } else {
+
+      pid = getpid();
+      while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
+
+        // in this function the fuzz magic happens, this is STEP 3
+        fuzz();
+
+        // we can use _exit which is faster because our target library
+        // was loaded via dlopen and therefore cannot have deconstructors
+        // registered.
+        _exit(0);
+
+      }
+
+    }
+
+  }
+
+  return 0;
+
+}
+
+#ifndef _DEBUG
+inline
+#endif
+    static void
+    fuzz(void) {
+
+  // STEP 3: call the function to fuzz, also the functions you might
+  //         need to call to prepare the function and - important! -
+  //         to clean everything up
+
+  // in this example we use the input file, not stdin!
+  (*o_function)(buf, len);
+
+  // normally you also need to cleanup
+  //(*o_LibFree)(foo);
+
+  // END STEP 3
+
+}
+
diff --git a/utils/afl_untracer/ghidra_get_patchpoints.java b/utils/afl_untracer/ghidra_get_patchpoints.java
new file mode 100644
index 00000000..2a93642b
--- /dev/null
+++ b/utils/afl_untracer/ghidra_get_patchpoints.java
@@ -0,0 +1,84 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Find patch points for untracer tools (e.g. afl++ utils/afl_untracer)
+//
+//   Copy to ..../Ghidra/Features/Search/ghidra_scripts/
+//   Writes the results to ~/Desktop/patches.txt
+//
+//   This is my very first Ghidra script. I am sure this could be done better.
+//
+//@category Search
+
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.address.*;
+import ghidra.program.model.block.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.mem.*;
+
+import java.io.*;
+
+public class ghidra_get_patchpoints extends GhidraScript {
+
+	@Override
+	public void run() throws Exception {
+
+		long segment_start = 0;
+		Memory memory = currentProgram.getMemory();
+		MultEntSubModel model = new MultEntSubModel(currentProgram);
+		CodeBlockIterator subIter = model.getCodeBlocks(monitor);
+		BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt"));
+
+		while (subIter.hasNext()) {
+
+			CodeBlock multiEntryBlock = subIter.next();
+			SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram);
+			CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor);
+
+			while (bbIter.hasNext()) {
+
+				CodeBlock basicBlock = bbIter.next();
+
+				if (segment_start == 0) {
+
+					Address firstAddr = basicBlock.getFirstStartAddress();
+					long firstBlockAddr = firstAddr.getAddressableWordOffset();
+					MemoryBlock mb = memory.getBlock(firstAddr);
+					Address startAddr = mb.getStart();
+					Address endAddr = mb.getEnd();
+					segment_start = startAddr.getAddressableWordOffset();
+					if ((firstBlockAddr - segment_start) >= 0x1000)
+					  segment_start += 0x1000;
+					long segment_end = endAddr.getAddressableWordOffset();
+					long segment_size = segment_end - segment_start;
+					if ((segment_size % 0x1000) > 0)
+					  segment_size = (((segment_size / 0x1000) + 1) * 0x1000);
+					out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n"); 
+					//println("Start: " + Long.toHexString(segment_start));
+					//println("End: " + Long.toHexString(segment_end));
+
+				}
+ 	   		        
+ 	   		        if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0)
+ 	   		        	out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n");
+
+			}
+		}
+
+		out.close();
+
+	}
+}
diff --git a/utils/afl_untracer/ida_get_patchpoints.py b/utils/afl_untracer/ida_get_patchpoints.py
new file mode 100644
index 00000000..807685b3
--- /dev/null
+++ b/utils/afl_untracer/ida_get_patchpoints.py
@@ -0,0 +1,63 @@
+#
+# IDAPython script for IDA Pro
+# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py
+#
+
+import idautils
+import idaapi
+import ida_nalt
+import idc
+
+# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml
+
+from os.path import expanduser
+
+home = expanduser("~")
+
+patchpoints = set()
+
+max_offset = 0
+for seg_ea in idautils.Segments():
+    name = idc.get_segm_name(seg_ea)
+    # print("Segment: " + name)
+    if name != "__text" and name != ".text":
+        continue
+
+    start = idc.get_segm_start(seg_ea)
+    end = idc.get_segm_end(seg_ea)
+    first = 0
+    subtract_addr = 0
+    # print("Start: " + hex(start) + " End: " + hex(end))
+    for func_ea in idautils.Functions(start, end):
+        f = idaapi.get_func(func_ea)
+        if not f:
+            continue
+        for block in idaapi.FlowChart(f):
+            if start <= block.start_ea < end:
+                if first == 0:
+                    if block.start_ea >= 0x1000:
+                        subtract_addr = 0x1000
+                        first = 1
+
+                max_offset = max(max_offset, block.start_ea)
+                patchpoints.add(block.start_ea - subtract_addr)
+            # else:
+            #    print("Warning: broken CFG?")
+
+# Round up max_offset to page size
+size = max_offset
+rem = size % 0x1000
+if rem != 0:
+    size += 0x1000 - rem
+
+print("Writing to " + home + "/Desktop/patches.txt")
+
+with open(home + "/Desktop/patches.txt", "w") as f:
+    f.write(ida_nalt.get_root_filename() + ":" + hex(size) + "\n")
+    f.write("\n".join(map(hex, sorted(patchpoints))))
+    f.write("\n")
+
+print("Done, found {} patchpoints".format(len(patchpoints)))
+
+# For headless script running remove the comment from the next line
+# ida_pro.qexit()
diff --git a/utils/afl_untracer/libtestinstr.c b/utils/afl_untracer/libtestinstr.c
new file mode 100644
index 00000000..96b1cf21
--- /dev/null
+++ b/utils/afl_untracer/libtestinstr.c
@@ -0,0 +1,35 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
diff --git a/utils/afl_untracer/patches.txt b/utils/afl_untracer/patches.txt
new file mode 100644
index 00000000..7e964249
--- /dev/null
+++ b/utils/afl_untracer/patches.txt
@@ -0,0 +1,34 @@
+libtestinstr.so:0x1000
+0x10
+0x12
+0x20
+0x36
+0x30
+0x40
+0x50
+0x63
+0x6f
+0x78
+0x80
+0xa4
+0xb0
+0xb8
+0x100
+0xc0
+0xc9
+0xd7
+0xe3
+0xe8
+0xf8
+0x105
+0x11a
+0x135
+0x141
+0x143
+0x14e
+0x15a
+0x15c
+0x168
+0x16a
+0x16b
+0x170
diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile
new file mode 100644
index 00000000..c1a087d7
--- /dev/null
+++ b/utils/aflpp_driver/GNUmakefile
@@ -0,0 +1,46 @@
+ifeq "" "$(LLVM_CONFIG)"
+  LLVM_CONFIG=llvm-config
+endif
+
+LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
+ifneq "" "$(LLVM_BINDIR)"
+  LLVM_BINDIR := $(LLVM_BINDIR)/
+endif
+
+CFLAGS := -O3 -funroll-loops -g
+
+all:	libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so
+
+aflpp_driver.o:	aflpp_driver.c
+	-$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c
+
+libAFLDriver.a:	aflpp_driver.o
+	ar ru libAFLDriver.a aflpp_driver.o
+	cp -vf libAFLDriver.a ../../
+
+debug:
+	$(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c
+	$(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
+	#$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c
+	#$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c
+	ar ru libAFLDriver.a afl-performance.o aflpp_driver.o
+
+aflpp_qemu_driver.o:	aflpp_qemu_driver.c
+	$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c
+
+libAFLQemuDriver.a:	aflpp_qemu_driver.o
+	ar ru libAFLQemuDriver.a aflpp_qemu_driver.o
+	cp -vf libAFLQemuDriver.a ../../
+
+aflpp_qemu_driver_hook.so:	aflpp_qemu_driver_hook.o
+	$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so
+
+aflpp_qemu_driver_hook.o:	aflpp_qemu_driver_hook.c
+	$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c
+
+test:	debug
+	#clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c
+	afl-clang-fast -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test aflpp_driver_test.c libAFLDriver.a afl-performance.o
+
+clean:
+	rm -f *.o libAFLDriver*.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so *~ core aflpp_driver_test
diff --git a/utils/aflpp_driver/Makefile b/utils/aflpp_driver/Makefile
new file mode 100644
index 00000000..3666a74d
--- /dev/null
+++ b/utils/aflpp_driver/Makefile
@@ -0,0 +1,2 @@
+all:
+	@gmake all || echo please install GNUmake
diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c
new file mode 100644
index 00000000..f0f3a47d
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_driver.c
@@ -0,0 +1,284 @@
+//===- afl_driver.cpp - a glue between AFL++ and libFuzzer ------*- C++ -* ===//
+//===----------------------------------------------------------------------===//
+
+/* This file allows to fuzz libFuzzer-style target functions
+ (LLVMFuzzerTestOneInput) with AFL++ using persistent in-memory fuzzing.
+
+Usage:
+################################################################################
+cat << EOF > test_fuzzer.cc
+#include <stddef.h>
+#include <stdint.h>
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+  if (size > 0 && data[0] == 'H')
+    if (size > 1 && data[1] == 'I')
+       if (size > 2 && data[2] == '!')
+       __builtin_trap();
+  return 0;
+
+}
+
+EOF
+# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
+clang -c aflpp_driver.c
+# Build afl-compiler-rt.o.c from the AFL distribution.
+clang -c $AFL_HOME/instrumentation/afl-compiler-rt.o.c
+# Build this file, link it with afl-compiler-rt.o.o and the target code.
+afl-clang-fast -o test_fuzzer test_fuzzer.cc afl-compiler-rt.o aflpp_driver.o
+# Run AFL:
+rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
+$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
+################################################################################
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "config.h"
+#include "types.h"
+#include "cmplog.h"
+
+#ifdef _DEBUG
+  #include "hash.h"
+#endif
+
+int                   __afl_sharedmem_fuzzing = 1;
+extern unsigned int * __afl_fuzz_len;
+extern unsigned char *__afl_fuzz_ptr;
+
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+// Notify AFL about persistent mode.
+static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
+int                  __afl_persistent_loop(unsigned int);
+
+// Notify AFL about deferred forkserver.
+static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
+void                 __afl_manual_init();
+
+// Use this optionally defined function to output sanitizer messages even if
+// user asks to close stderr.
+__attribute__((weak)) void __sanitizer_set_report_fd(void *);
+
+// Keep track of where stderr content is being written to, so that
+// dup_and_close_stderr can use the correct one.
+static FILE *output_file;
+
+// Experimental feature to use afl_driver without AFL's deferred mode.
+// Needs to run before __afl_auto_init.
+__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
+
+  if (getenv("AFL_DRIVER_DONT_DEFER")) {
+
+    if (unsetenv("__AFL_DEFER_FORKSRV")) {
+
+      perror("Failed to unset __AFL_DEFER_FORKSRV");
+      abort();
+
+    }
+
+  }
+
+}
+
+// If the user asks us to duplicate stderr, then do it.
+static void maybe_duplicate_stderr() {
+
+  char *stderr_duplicate_filename =
+      getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
+
+  if (!stderr_duplicate_filename) return;
+
+  FILE *stderr_duplicate_stream =
+      freopen(stderr_duplicate_filename, "a+", stderr);
+
+  if (!stderr_duplicate_stream) {
+
+    fprintf(
+        stderr,
+        "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
+    abort();
+
+  }
+
+  output_file = stderr_duplicate_stream;
+
+}
+
+// Most of these I/O functions were inspired by/copied from libFuzzer's code.
+static void discard_output(int fd) {
+
+  FILE *temp = fopen("/dev/null", "w");
+  if (!temp) abort();
+  dup2(fileno(temp), fd);
+  fclose(temp);
+
+}
+
+static void close_stdout() {
+
+  discard_output(STDOUT_FILENO);
+
+}
+
+// Prevent the targeted code from writing to "stderr" but allow sanitizers and
+// this driver to do so.
+static void dup_and_close_stderr() {
+
+  int output_fileno = fileno(output_file);
+  int output_fd = dup(output_fileno);
+  if (output_fd <= 0) abort();
+  FILE *new_output_file = fdopen(output_fd, "w");
+  if (!new_output_file) abort();
+  if (!__sanitizer_set_report_fd) return;
+  __sanitizer_set_report_fd((void *)(long int)output_fd);
+  discard_output(output_fileno);
+
+}
+
+// Close stdout and/or stderr if user asks for it.
+static void maybe_close_fd_mask() {
+
+  char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
+  if (!fd_mask_str) return;
+  int fd_mask = atoi(fd_mask_str);
+  if (fd_mask & 2) dup_and_close_stderr();
+  if (fd_mask & 1) close_stdout();
+
+}
+
+// Define LLVMFuzzerMutate to avoid link failures for targets that use it
+// with libFuzzer's LLVMFuzzerCustomMutator.
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+
+  // assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
+  return 0;
+
+}
+
+// Execute any files provided as parameters.
+static int ExecuteFilesOnyByOne(int argc, char **argv) {
+
+  unsigned char *buf = (unsigned char *)malloc(MAX_FILE);
+  for (int i = 1; i < argc; i++) {
+
+    int fd = open(argv[i], O_RDONLY);
+    if (fd == -1) continue;
+    ssize_t length = read(fd, buf, MAX_FILE);
+    if (length > 0) {
+
+      printf("Reading %zu bytes from %s\n", length, argv[i]);
+      LLVMFuzzerTestOneInput(buf, length);
+      printf("Execution successful.\n");
+
+    }
+
+  }
+
+  free(buf);
+  return 0;
+
+}
+
+int main(int argc, char **argv) {
+
+  printf(
+      "======================= INFO =========================\n"
+      "This binary is built for afl++.\n"
+      "To run the target function on individual input(s) execute this:\n"
+      "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
+      "To fuzz with afl-fuzz execute this:\n"
+      "  afl-fuzz [afl-flags] -- %s [-N]\n"
+      "afl-fuzz will run N iterations before re-spawning the process (default: "
+      "INT_MAX)\n"
+      "======================================================\n",
+      argv[0], argv[0]);
+
+  if (getenv("AFL_GDB")) {
+
+    char cmd[64];
+    snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
+    system(cmd);
+    fprintf(stderr, "DEBUG: aflpp_driver pid is %d\n", getpid());
+    sleep(1);
+
+  }
+
+  output_file = stderr;
+  maybe_duplicate_stderr();
+  maybe_close_fd_mask();
+  if (LLVMFuzzerInitialize) {
+
+    fprintf(stderr, "Running LLVMFuzzerInitialize ...\n");
+    LLVMFuzzerInitialize(&argc, &argv);
+    fprintf(stderr, "continue...\n");
+
+  }
+
+  // Do any other expensive one-time initialization here.
+
+  uint8_t dummy_input[64] = {0};
+  memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT));
+  memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR,
+         sizeof(AFL_DEFER_FORKSVR));
+  int N = INT_MAX;
+  if (argc == 2 && argv[1][0] == '-')
+    N = atoi(argv[1] + 1);
+  else if (argc == 2 && (N = atoi(argv[1])) > 0)
+    printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
+  else if (argc > 1) {
+
+    __afl_sharedmem_fuzzing = 0;
+    __afl_manual_init();
+    return ExecuteFilesOnyByOne(argc, argv);
+
+  }
+
+  assert(N > 0);
+
+  //  if (!getenv("AFL_DRIVER_DONT_DEFER"))
+  __afl_manual_init();
+
+  // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
+  // on the first execution of LLVMFuzzerTestOneInput is ignored.
+  LLVMFuzzerTestOneInput(dummy_input, 1);
+
+  int num_runs = 0;
+  while (__afl_persistent_loop(N)) {
+
+#ifdef _DEBUG
+    fprintf(stderr, "CLIENT crc: %016llx len: %u\n",
+            hash64(__afl_fuzz_ptr, *__afl_fuzz_len, 0xa5b35705),
+            *__afl_fuzz_len);
+    fprintf(stderr, "RECV:");
+    for (int i = 0; i < *__afl_fuzz_len; i++)
+      fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
+    fprintf(stderr, "\n");
+#endif
+    if (*__afl_fuzz_len) {
+
+      num_runs++;
+      LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
+
+    }
+
+  }
+
+  printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_driver_test.c b/utils/aflpp_driver/aflpp_driver_test.c
new file mode 100644
index 00000000..fe05b4f8
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_driver_test.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "hash.h"
+
+void __attribute__((noinline)) crashme(const uint8_t *Data, size_t Size) {
+
+  if (Size < 5) return;
+
+  if (Data[0] == 'F')
+    if (Data[1] == 'A')
+      if (Data[2] == '$')
+        if (Data[3] == '$')
+          if (Data[4] == '$') abort();
+
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+
+  if (Size) crashme(Data, Size);
+
+  return 0;
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_qemu_driver.c b/utils/aflpp_driver/aflpp_qemu_driver.c
new file mode 100644
index 00000000..79de5af6
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_qemu_driver.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+#define kMaxAflInputSize (1 * 1024 * 1024)
+static uint8_t AflInputBuf[kMaxAflInputSize];
+
+void __attribute__((noinline)) afl_qemu_driver_stdin_input(void) {
+
+  size_t l = read(0, AflInputBuf, kMaxAflInputSize);
+  LLVMFuzzerTestOneInput(AflInputBuf, l);
+
+}
+
+int main(int argc, char **argv) {
+
+  if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv);
+  // Do any other expensive one-time initialization here.
+
+  if (getenv("AFL_QEMU_DRIVER_NO_HOOK")) {
+
+    afl_qemu_driver_stdin_input();
+
+  } else {
+
+    uint8_t dummy_input[1024000] = {0};
+    LLVMFuzzerTestOneInput(dummy_input, 1);
+
+  }
+
+  return 0;
+
+}
+
diff --git a/utils/aflpp_driver/aflpp_qemu_driver_hook.c b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
new file mode 100644
index 00000000..823cc42d
--- /dev/null
+++ b/utils/aflpp_driver/aflpp_qemu_driver_hook.c
@@ -0,0 +1,22 @@
+#include <stdint.h>
+#include <string.h>
+
+#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+
+#define REGS_RDI 7
+#define REGS_RSI 6
+
+void afl_persistent_hook(uint64_t *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_len) {
+
+  memcpy(g2h(regs[REGS_RDI]), input_buf, input_len);
+  regs[REGS_RSI] = input_len;
+
+}
+
+int afl_persistent_hook_init(void) {
+
+  return 1;
+
+}
+
diff --git a/utils/analysis_scripts/queue2csv.sh b/utils/analysis_scripts/queue2csv.sh
new file mode 100755
index 00000000..2528b438
--- /dev/null
+++ b/utils/analysis_scripts/queue2csv.sh
@@ -0,0 +1,122 @@
+#!/bin/bash
+
+test -z "$1" -o -z "$2" -o "$1" = "-h" -o "$1" = "-hh" -o "$1" = "--help" -o '!' -d "$1" && {
+  echo "Syntax: [-n]  $0 out-directory file.csv [\"tools/target --opt @@\"]"
+  echo Option -n will suppress the CSV header.
+  echo If the target execution command is supplied then also edge coverage is gathered.
+  exit 1
+}
+
+function getval() {
+  VAL=""
+  if [ "$file" != "${file/$1/}" ]; then
+    TMP="${file/*$1:/}"
+    VAL="${TMP/,*/}"
+  fi
+}
+
+SKIP=
+if [ "$1" = "-n" ]; then
+  SKIP=1
+  shift
+fi
+
+test -n "$4" && { echo "Error: too many commandline options. Target command and options including @@ have to be passed within \"\"!"; exit 1; }
+
+test -d "$1"/queue && OUT="$1/queue" || OUT="$1"
+
+OK=`ls $OUT/id:000000,time:0,orig:* 2> /dev/null`
+if [ -n "$OK" ]; then
+  LISTCMD="ls $OUT/id:"*
+else
+  LISTCMD="ls -tr $OUT/"
+fi
+
+ID=;SRC=;TIME=;OP=;POS=;REP=;EDGES=;EDGES_TOTAL=;
+DIR="$OUT/../stats"
+rm -rf "$DIR"
+> "$2" || exit 1
+mkdir "$DIR" || exit 1
+> "$DIR/../edges.txt" || exit 1
+
+{
+
+  if [ -z "$SKIP" ]; then
+    echo "time;\"filename\";id;src;new_cov;edges;total_edges;\"op\";pos;rep;unique_edges"
+  fi
+
+  $LISTCMD | grep -v ,sync: | sed 's/.*id:/id:/g' | while read file; do
+
+    if [ -n "$3" ]; then
+
+      TMP=${3/@@/$OUT/$file}
+      
+      if [ "$TMP" = "$3" ]; then
+    
+        cat "$OUT/$file" | afl-showmap -o "$DIR/$file" -q -- $3 >/dev/null 2>&1
+        
+      else
+      
+        afl-showmap -o "$DIR/$file" -q -- $TMP >/dev/null 2>&1
+      
+      fi
+    
+      { cat "$DIR/$file" | sed 's/:.*//' ; cat "$DIR/../edges.txt" ; } | sort -nu > $DIR/../edges.txt.tmp
+      mv $DIR/../edges.txt.tmp $DIR/../edges.txt
+      EDGES=$(cat "$DIR/$file" | wc -l)
+      EDGES_TOTAL=$(cat "$DIR/../edges.txt" | wc -l)
+
+    fi
+
+    getval id; ID="$VAL"
+    getval src; SRC="$VAL"
+    getval time; TIME="$VAL"
+    getval op; OP="$VAL"
+    getval pos; POS="$VAL"
+    getval rep; REP="$VAL"
+    if [ "$file" != "${file/+cov/}" ]; then
+      COV=1
+    else
+      COV=""
+    fi
+
+    if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then
+      echo "$TIME;\"$file\";$ID;$SRC;$COV;$EDGES;$EDGES_TOTAL;\"$OP\";$POS;$REP;UNIQUE$file"
+    else
+      echo "$TIME;\"$file\";$ID;$SRC;$COV;;;\"$OP\";$POS;$REP;"
+    fi
+
+  done
+
+} | tee "$DIR/../queue.csv" > "$2" || exit 1
+
+if [ -n "$3" -a -s "$DIR/../edges.txt" ]; then
+
+  cat "$DIR/"* | sed 's/:.*//' | sort -n | uniq -c | egrep '^[ \t]*1 ' | awk '{print$2}' > $DIR/../unique.txt
+
+  if [ -s "$DIR/../unique.txt" ]; then
+
+    ls "$DIR/id:"* | grep -v ",sync:" |sed 's/.*\/id:/id:/g' | while read file; do
+
+      CNT=$(sed 's/:.*//' "$DIR/$file" | tee "$DIR/../tmp.txt" | wc -l)
+      DIFF=$(diff -u "$DIR/../tmp.txt" "$DIR/../unique.txt" | egrep '^-[0-9]' | wc -l)
+      UNIQUE=$(($CNT - $DIFF))
+      sed -i "s/;UNIQUE$file/;$UNIQUE/" "$DIR/../queue.csv" "$2"
+
+    done
+    
+    rm -f "$DIR/../tmp.txt"
+
+  else
+    
+    sed -i 's/;UNIQUE.*/;/' "$DIR/../queue.csv" "$2"
+  
+  fi  
+
+fi
+
+mv "$DIR/../queue.csv" "$DIR/queue.csv"
+if [ -e "$DIR/../edges.txt" ]; then mv "$DIR/../edges.txt" "$DIR/edges.txt"; fi
+if [ -e "$DIR/../unique.txt" ]; then mv "$DIR/../unique.txt" "$DIR/unique.txt"; fi
+
+echo "Created $2"
diff --git a/utils/argv_fuzzing/Makefile b/utils/argv_fuzzing/Makefile
new file mode 100644
index 00000000..5a0ac6e6
--- /dev/null
+++ b/utils/argv_fuzzing/Makefile
@@ -0,0 +1,58 @@
+#
+# american fuzzy lop++ - argvfuzz
+# --------------------------------
+#
+# Copyright 2019-2020 Kjell Braden <afflux@pentabarf.de>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS  += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+
+all: argvfuzz32.so argvfuzz64.so
+
+argvfuzz32.so: argvfuzz.c
+	-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz32 build failure (that's fine)"
+
+argvfuzz64.so: argvfuzz.c
+	-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "argvfuzz64 build failure (that's fine)"
+
+install: argvfuzz32.so argvfuzz64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	if [ -f argvfuzz64.so ]; then set -e; install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+clean:
+	rm -f argvfuzz32.so argvfuzz64.so
diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md
new file mode 100644
index 00000000..fa8cad80
--- /dev/null
+++ b/utils/argv_fuzzing/README.md
@@ -0,0 +1,16 @@
+# argvfuzz
+
+afl supports fuzzing file inputs or stdin. When source is available,
+`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin.
+
+`argvfuzz` tries to provide the same functionality for binaries. When loaded
+using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace
+argv using the same logic of `argv-fuzz-inl.h`.
+
+A few conditions need to be fulfilled for this mechanism to work correctly:
+
+1. As it relies on hooking the loader, it cannot work on static binaries.
+2. If the target binary does not use the default libc's `_start` implementation
+   (crt1.o), the hook may not run.
+3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the
+   target binary expects argv to be living on the stack, things may go wrong.
diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h
new file mode 100644
index 00000000..c15c0271
--- /dev/null
+++ b/utils/argv_fuzzing/argv-fuzz-inl.h
@@ -0,0 +1,90 @@
+/*
+   american fuzzy lop++ - sample argv fuzzing wrapper
+   ------------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2015 Google Inc. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   This file shows a simple way to fuzz command-line parameters with stock
+   afl-fuzz. To use, add:
+
+   #include "/path/to/argv-fuzz-inl.h"
+
+   ...to the file containing main(), ideally placing it after all the
+   standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of
+   main().
+
+   This will cause the program to read NUL-delimited input from stdin and
+   put it in argv[]. Two subsequent NULs terminate the array. Empty
+   params are encoded as a lone 0x02. Lone 0x02 can't be generated, but
+   that shouldn't matter in real life.
+
+   If you would like to always preserve argv[0], use this instead:
+   AFL_INIT_SET0("prog_name");
+
+*/
+
+#ifndef _HAVE_ARGV_FUZZ_INL
+#define _HAVE_ARGV_FUZZ_INL
+
+#include <unistd.h>
+
+#define AFL_INIT_ARGV()          \
+  do {                           \
+                                 \
+    argv = afl_init_argv(&argc); \
+                                 \
+  } while (0)
+
+#define AFL_INIT_SET0(_p)        \
+  do {                           \
+                                 \
+    argv = afl_init_argv(&argc); \
+    argv[0] = (_p);              \
+    if (!argc) argc = 1;         \
+                                 \
+  } while (0)
+
+#define MAX_CMDLINE_LEN 100000
+#define MAX_CMDLINE_PAR 50000
+
+static char **afl_init_argv(int *argc) {
+
+  static char  in_buf[MAX_CMDLINE_LEN];
+  static char *ret[MAX_CMDLINE_PAR];
+
+  char *ptr = in_buf;
+  int   rc = 0;
+
+  if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {}
+
+  while (*ptr && rc < MAX_CMDLINE_PAR) {
+
+    ret[rc] = ptr;
+    if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++;
+    rc++;
+
+    while (*ptr)
+      ptr++;
+    ptr++;
+
+  }
+
+  *argc = rc;
+
+  return ret;
+
+}
+
+#undef MAX_CMDLINE_LEN
+#undef MAX_CMDLINE_PAR
+
+#endif                                              /* !_HAVE_ARGV_FUZZ_INL */
+
diff --git a/utils/argv_fuzzing/argvfuzz.c b/utils/argv_fuzzing/argvfuzz.c
new file mode 100644
index 00000000..4251ca4c
--- /dev/null
+++ b/utils/argv_fuzzing/argvfuzz.c
@@ -0,0 +1,49 @@
+/*
+   american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries
+   ------------------------------------------------------------
+
+   Copyright 2019-2020 Kjell Braden <afflux@pentabarf.de>
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+ */
+
+#define _GNU_SOURCE                                        /* for RTLD_NEXT */
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "argv-fuzz-inl.h"
+
+int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
+                      void (*init)(void), void (*fini)(void),
+                      void (*rtld_fini)(void), void *stack_end) {
+
+  int (*orig)(int (*main)(int, char **, char **), int argc, char **argv,
+              void (*init)(void), void (*fini)(void), void (*rtld_fini)(void),
+              void *stack_end);
+  int    sub_argc;
+  char **sub_argv;
+
+  (void)argc;
+  (void)argv;
+
+  orig = dlsym(RTLD_NEXT, __func__);
+
+  if (!orig) {
+
+    fprintf(stderr, "hook did not find original %s: %s\n", __func__, dlerror());
+    exit(EXIT_FAILURE);
+
+  }
+
+  sub_argv = afl_init_argv(&sub_argc);
+
+  return orig(main, sub_argc, sub_argv, init, fini, rtld_fini, stack_end);
+
+}
+
diff --git a/utils/asan_cgroups/limit_memory.sh b/utils/asan_cgroups/limit_memory.sh
new file mode 100755
index 00000000..1f0f04ad
--- /dev/null
+++ b/utils/asan_cgroups/limit_memory.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+#
+# american fuzzy lop++ - limit memory using cgroups
+# -----------------------------------------------
+#
+# Written by Samir Khakimov <samir.hakim@nyu.edu> and
+#            David A. Wheeler <dwheeler@ida.org>
+#
+# Edits to bring the script in line with afl-cmin and other companion scripts
+# by Michal Zalewski. All bugs are my fault.
+#
+# Copyright 2015 Institute for Defense Analyses.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+# This tool allows the amount of actual memory allocated to a program
+# to be limited on Linux systems using cgroups, instead of the traditional
+# setrlimit() API. This helps avoid the address space problems discussed in
+# docs/notes_for_asan.md.
+#
+# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some
+# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed
+# task.
+#
+
+echo "cgroup tool for afl-fuzz by <samir.hakim@nyu.edu> and <dwheeler@ida.org>"
+echo
+
+unset NEW_USER
+MEM_LIMIT="50"
+
+while getopts "+u:m:" opt; do
+
+  case "$opt" in
+
+    "u")
+         NEW_USER="$OPTARG"
+         ;;
+
+    "m")
+         MEM_LIMIT="$[OPTARG]"
+         ;;
+
+    "?")
+         exit 1
+         ;;
+
+   esac
+
+done
+
+if [ "$MEM_LIMIT" -lt "5" ]; then
+  echo "[-] Error: malformed or dangerously low value of -m." 1>&2
+  exit 1
+fi
+
+shift $((OPTIND-1))
+
+TARGET_BIN="$1"
+
+if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then
+
+  cat 1>&2 <<_EOF_
+Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ]
+
+Required parameters:
+
+  -u user   - run the fuzzer as a specific user after setting up limits
+
+Optional parameters:
+
+  -m megs   - set memory limit to a specified value ($MEM_LIMIT MB)
+
+This tool configures cgroups-based memory limits for a fuzzing job to simplify
+the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in
+conjunction with '-m none' passed to the afl-fuzz binary itself, say:
+
+  $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target
+
+_EOF_
+
+  exit 1
+
+fi
+
+# Basic sanity checks
+
+if [ ! "`uname -s`" = "Linux" ]; then
+ echo "[-] Error: this tool does not support non-Linux systems." 1>&2
+ exit 1
+fi
+
+if [ ! "`id -u`" = "0" ]; then
+ echo "[-] Error: you need to run this script as root (sorry!)." 1>&2
+ exit 1
+fi
+
+if ! type cgcreate 2>/dev/null 1>&2; then
+
+  echo "[-] Error: you need to install cgroup tools first." 1>&2
+
+  if type apt-get 2>/dev/null 1>&2; then
+    echo "    (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2
+  elif type yum 2>/dev/null 1>&2; then
+    echo "    (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2
+  fi
+
+  exit 1
+
+fi
+
+if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then
+  echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2
+  exit 1
+fi
+
+# Create a new cgroup path if necessary... We used PID-keyed groups to keep
+# parallel afl-fuzz tasks separate from each other.
+
+CID="afl-$NEW_USER-$$"
+
+CPATH="/sys/fs/cgroup/memory/$CID"
+
+if [ ! -d "$CPATH" ]; then
+
+  cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1
+
+fi
+
+# Set the appropriate limit...
+
+if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then
+
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+elif grep -qE 'partition|file' /proc/swaps; then
+
+  echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2
+  exit 1
+
+else
+
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+fi
+
+# All right. At this point, we can just run the command.
+
+cgexec -g "memory:$CID" su -c "$*" "$NEW_USER"
+
+cgdelete -g "memory:$CID"
diff --git a/utils/bash_shellshock/shellshock-fuzz.diff b/utils/bash_shellshock/shellshock-fuzz.diff
new file mode 100644
index 00000000..3fa05bf8
--- /dev/null
+++ b/utils/bash_shellshock/shellshock-fuzz.diff
@@ -0,0 +1,59 @@
+This patch shows a very simple way to find post-Shellshock bugs in bash, as
+discussed here:
+
+  http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html
+
+In essence, it shows a way to fuzz environmental variables. Instructions:
+
+1) Download bash 4.3, apply this patch, compile with:
+
+   CC=/path/to/afl-gcc ./configure
+   make clean all
+
+   Note that the harness puts the fuzzed output in $TEST_VARIABLE. With
+   Florian's Shellshock patch (bash43-028), this is no longer passed down
+   to the parser.
+
+2) Create and cd to an empty directory, put the compiled bash binary in
+   there, and run these commands:
+
+   mkdir in_dir
+   echo -n '() { a() { a; }; : >b; }' >in_dir/script.txt
+
+3) Run the fuzzer with:
+
+   /path/to/afl-fuzz -d -i in_dir -o out_dir ./bash -c :
+
+   The -d parameter is advisable only if the tested shell is fairly slow
+   or if you are in a hurry; will cover more ground faster, but
+   less systematically.
+
+4) Watch for crashes in out_dir/crashes/. Also watch for any new files
+   created in cwd if you're interested in non-crash RCEs (files will be
+   created whenever the shell executes "foo>bar" or something like
+   that). You can correlate their creation date with new entries in
+   out_dir/queue/.
+
+   You can also modify the bash binary to directly check for more subtle
+   fault conditions, or use the synthesized entries in out_dir/queue/
+   as a seed for other, possibly slower or more involved testing regimes.
+
+   Expect several hours to get decent coverage.
+
+--- bash-4.3/shell.c.orig	2014-01-14 14:04:32.000000000 +0100
++++ bash-4.3/shell.c	2015-04-30 05:56:46.000000000 +0200
+@@ -371,6 +371,14 @@
+   env = environ;
+ #endif /* __OPENNT */
+ 
++  {
++
++    static char val[1024 * 16];
++    read(0, val, sizeof(val) - 1);
++    setenv("TEST_VARIABLE", val, 1);
++
++  }
++
+   USE_VAR(argc);
+   USE_VAR(argv);
+   USE_VAR(env);
diff --git a/utils/canvas_harness/canvas_harness.html b/utils/canvas_harness/canvas_harness.html
new file mode 100644
index 00000000..a37b6937
--- /dev/null
+++ b/utils/canvas_harness/canvas_harness.html
@@ -0,0 +1,170 @@
+<html>
+<!--
+
+  american fuzzy lop++ - <canvas> harness
+  -------------------------------------
+ 
+  Originally written by Michal Zalewski
+ 
+  Copyright 2013, 2014 Google Inc. All rights reserved.
+ 
+  Licensed under the Apache License, Version 2.0 (the "License");
+  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
+ 
+  A simple harness for going through afl-generated test cases, rendering them in
+  the browser environment, and discovering the use of uninitialized memory and
+  similar bugs. This code led to the discovery of a fair number of library and
+  browser security bugs!
+
+  The url_list[] array is a placeholder; for this to work properly, it needs to
+  be initialized with web-reachable paths to individual test cases. This can
+  be done manually or with a simple script.
+
+-->
+
+<body onload="set_images()">
+
+<div id="status"></div>
+
+<div id="image_div"></div>
+
+<canvas height=64 width=64 id=cvs></canvas>
+
+<h2>Results</h2>
+
+<ul id="output"></ul>
+
+<script>
+
+var c = document.getElementById('cvs');
+var ctx = c.getContext('2d');
+
+var url_list = [
+  "images/id:000000,[...].jpg",
+  "images/id:000001,[...].jpg",
+  /* ... */
+  null
+];
+
+var USE_IMAGES = 50;
+var cur_image = 0;
+
+if (location.hash) cur_image = parseInt(location.hash.substr(1));
+
+var loaded = 0;
+var image_obj = [];
+
+var msie_cleanup;
+
+function check_results() {
+
+  var uniques = [];
+
+  clearTimeout(msie_cleanup);
+
+  ctx.clearRect(0, 0, 64, 64);
+
+  uniques.push(image_obj[0].imgdata);
+
+  for (var i = 1; i < USE_IMAGES; i++) {
+
+    if (!image_obj[i].imgdata) continue;
+
+    if (image_obj[0].imgdata != image_obj[i].imgdata) {
+
+      for (var j = 1; j < uniques.length; j++)
+        if (uniques[j] == image_obj[i].imgdata) break;
+
+      if (j == uniques.length) uniques.push(image_obj[i].imgdata);
+
+
+    }
+
+  }
+
+  if (uniques.length > 1) {
+
+    var str = '<li> Image ' + url_list[cur_image] + ' has ' + uniques.length + ' variants: ';
+
+    for (var i = 0; i < uniques.length; i++)
+      str += '<img src="' + uniques[i] + '">';
+
+    document.getElementById('output').innerHTML += str;
+
+  }
+
+  cur_image++;
+  set_images();
+}
+
+
+function count_image() {
+
+  if (!this.complete || this.counted) return;
+
+  this.counted = true;
+
+  loaded++;
+
+  ctx.clearRect(0, 0, 64, 64);
+
+  try {
+    ctx.drawImage(this, 0, 0, 64, 64);
+  } catch (e) { }
+
+  this.imgdata = c.toDataURL();
+
+  if (loaded == USE_IMAGES) check_results();
+}
+
+
+function set_images() {
+
+  loaded = 0;
+
+  document.getElementById('status').innerHTML = 'Now processing ' + cur_image + '...';
+  location.hash = '#' + cur_image;
+
+  if (url_list[cur_image] == null) {
+    alert('Done!');
+    return;
+  }
+
+  restart_images();
+
+  msie_cleanup = setTimeout(check_results, 5000);
+
+  for (var i = 0; i < USE_IMAGES; i++)
+    image_obj[i].src = url_list[cur_image] + '?' + Math.random();
+
+}
+
+
+function restart_images() {
+
+  for (var i = 0; i < USE_IMAGES; i++) 
+    if (image_obj[i]) image_obj[i].counted = true;
+
+  document.getElementById('image_div').innerHTML = '';
+  image_obj = [];
+
+  for (var i = 0; i < USE_IMAGES; i++) {
+
+    image_obj[i] = new Image();
+    image_obj[i].height = 64;
+    image_obj[i].width = 64;
+    image_obj[i].onerror = count_image;
+    image_obj[i].onload = count_image;
+
+    document.getElementById('image_div').appendChild(image_obj[i]);
+
+  }
+
+}
+
+</script>
+
+<iframe src='http://www.cnn.com/'></iframe>
diff --git a/utils/clang_asm_normalize/as b/utils/clang_asm_normalize/as
new file mode 100755
index 00000000..45537cae
--- /dev/null
+++ b/utils/clang_asm_normalize/as
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - clang assembly normalizer
+# ----------------------------------------------
+#
+# Originally written by Michal Zalewski
+# The idea for this wrapper comes from Ryan Govostes.
+#
+# Copyright 2013, 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+# This 'as' wrapper should allow you to instrument unruly, hand-written
+# assembly with afl-as.
+#
+# Usage:
+#
+# export AFL_REAL_PATH=/path/to/directory/with/afl-as/
+# AFL_PATH=/path/to/this/directory/ make clean all
+
+if [ "$#" -lt "2" ]; then
+  echo "[-] Error: this utility can't be called directly." 1>&2
+  exit 1
+fi
+
+if [ "$AFL_REAL_PATH" = "" ]; then
+  echo "[-] Error: AFL_REAL_PATH not set!" 1>&2
+  exit 1
+fi
+
+if [ ! -x "$AFL_REAL_PATH/afl-as" ]; then
+  echo "[-] Error: AFL_REAL_PATH does not contain the 'afl-as' binary." 1>&2
+  exit 1
+fi
+
+unset __AFL_AS_CMDLINE __AFL_FNAME
+
+while [ ! "$#" = "0" ]; do
+
+  if [ "$#" = "1" ]; then
+    __AFL_FNAME="$1"
+  else
+    __AFL_AS_CMDLINE="${__AFL_AS_CMDLINE} $1"
+  fi
+
+  shift
+
+done
+
+test "$TMPDIR" = "" && TMPDIR=/tmp
+
+TMPFILE=`mktemp $TMPDIR/.afl-XXXXXXXXXX.s`
+
+test "$TMPFILE" = "" && exit 1
+
+clang -cc1as -filetype asm -output-asm-variant 0 "${__AFL_FNAME}" >"$TMPFILE"
+
+ERR="$?"
+
+if [ ! "$ERR" = "0" ]; then
+  rm -f "$TMPFILE"
+  exit $ERR
+fi
+
+"$AFL_REAL_PATH/afl-as" ${__AFL_AS_CMDLINE} "$TMPFILE"
+
+ERR="$?"
+
+rm -f "$TMPFILE"
+
+exit "$ERR"
diff --git a/utils/crash_triage/triage_crashes.sh b/utils/crash_triage/triage_crashes.sh
new file mode 100755
index 00000000..a752458d
--- /dev/null
+++ b/utils/crash_triage/triage_crashes.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - crash triage utility
+# -----------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2013, 2014, 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+# Note that this assumes that the targeted application reads from stdin
+# and requires no other cmdline parameters. Modify as needed if this is
+# not the case.
+#
+# Note that on OpenBSD, you may need to install a newer version of gdb
+# (e.g., from ports). You can set GDB=/some/path to point to it if
+# necessary.
+#
+
+echo "crash triage utility for afl-fuzz by Michal Zalewski"
+echo
+
+ulimit -v 100000 2>/dev/null
+ulimit -d 100000 2>/dev/null
+
+if [ "$#" -lt "2" ]; then
+  echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2
+  echo 1>&2
+  exit 1
+fi
+
+DIR="$1"
+BIN="$2"
+shift
+shift
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+  echo "$DIR" | grep -qE '^(/var)?/tmp/'
+  T1="$?"
+
+  echo "$BIN" | grep -qE '^(/var)?/tmp/'
+  T2="$?"
+
+  if [ "$T1" = "0" -o "$T2" = "0" ]; then
+    echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+    exit 1
+  fi
+
+fi
+
+if
+ [ "$GDB" = "" ]; then
+  GDB=gdb
+fi
+
+if [ ! -f "$BIN" -o ! -x "$BIN" ]; then
+  echo "[-] Error: binary '$BIN' not found or is not executable." 1>&2
+  exit 1
+fi
+
+if [ ! -d "$DIR/queue" ]; then
+  echo "[-] Error: directory '$DIR' not found or not created by afl-fuzz." 1>&2
+  exit 1
+fi
+
+CCOUNT=$((`ls -- "$DIR/crashes" 2>/dev/null | wc -l`))
+
+if [ "$CCOUNT" = "0" ]; then
+  echo "No crashes recorded in the target directory - nothing to be done."
+  exit 0
+fi
+
+echo
+
+for crash in $DIR/crashes/id:*; do
+
+  id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2`
+  sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2`
+
+  # Grab the args, converting @@ to $crash
+
+  use_args=""
+  use_stdio=1
+
+  for a in $@; do
+
+    if [ "$a" = "@@" ] ; then
+      use_args="$use_args $crash"
+      unset use_stdio
+    else
+      use_args="$use_args $a"
+    fi
+
+  done
+
+  # Strip the trailing space
+  use_args="${use_args# }"
+
+  echo "+++ ID $id, SIGNAL $sig +++"
+  echo
+
+  if [ "$use_stdio" = "1" ]; then  
+    $GDB --batch -q --ex "r $use_args <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+  else
+    $GDB --batch -q --ex "r $use_args" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+  fi
+  echo
+
+done
diff --git a/utils/custom_mutators/Makefile b/utils/custom_mutators/Makefile
new file mode 100644
index 00000000..9849f3f4
--- /dev/null
+++ b/utils/custom_mutators/Makefile
@@ -0,0 +1,7 @@
+all: libexamplemutator.so
+
+libexamplemutator.so:
+	$(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so
+
+clean:
+	rm -rf libexamplemutator.so
diff --git a/utils/custom_mutators/README.md b/utils/custom_mutators/README.md
new file mode 100644
index 00000000..655f7a5e
--- /dev/null
+++ b/utils/custom_mutators/README.md
@@ -0,0 +1,35 @@
+# Examples for the custom mutator
+
+These are example and helper files for the custom mutator feature.
+See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
+
+Note that if you compile with python3.7 you must use python3 scripts, and if
+you use python2.7 to compile python2 scripts!
+
+simple_example.c - most simplest example. generates a random sized buffer
+          filled with 'A'
+
+example.c - this is a simple example written in C and should be compiled to a
+          shared library. Use make to compile it and produce libexamplemutator.so
+
+example.py - this is the template you can use, the functions are there but they
+           are empty
+
+post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF
+
+post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG
+
+simple-chunk-replace.py - this is a simple example where chunks are replaced
+
+common.py - this can be used for common functions and helpers.
+          the examples do not use this though. But you can :)
+
+wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
+
+XmlMutatorMin.py - module for XML mutation
+
+custom_mutator_helpers.h is an header that defines some helper routines
+like surgical_havoc_mutate() that allow to perform a randomly chosen
+mutation from a subset of the havoc mutations.
+If you do so, you have to specify -I /path/to/AFLplusplus/include when
+compiling.
diff --git a/utils/custom_mutators/XmlMutatorMin.py b/utils/custom_mutators/XmlMutatorMin.py
new file mode 100644
index 00000000..3e6cd0ff
--- /dev/null
+++ b/utils/custom_mutators/XmlMutatorMin.py
@@ -0,0 +1,348 @@
+#!/usr/bin/python
+
+""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """
+
+from __future__ import print_function
+from copy import deepcopy
+from lxml import etree as ET
+import random, re, io
+
+
+###########################
+# The XmlMutatorMin class #
+###########################
+
+
+class XmlMutatorMin:
+
+    """
+    Optionals parameters:
+        seed        Seed used by the PRNG (default: "RANDOM")
+        verbose     Verbosity (default: False)
+    """
+
+    def __init__(self, seed="RANDOM", verbose=False):
+
+        """ Initialize seed, database and mutators """
+
+        # Verbosity
+        self.verbose = verbose
+
+        # Initialize PRNG
+        self.seed = str(seed)
+        if self.seed == "RANDOM":
+            random.seed()
+        else:
+            if self.verbose:
+                print("Static seed '%s'" % self.seed)
+            random.seed(self.seed)
+
+        # Initialize input and output documents
+        self.input_tree = None
+        self.tree = None
+
+        # High-level mutators (no database needed)
+        hl_mutators_delete = [
+            "del_node_and_children",
+            "del_node_but_children",
+            "del_attribute",
+            "del_content",
+        ]  # Delete items
+        hl_mutators_fuzz = ["fuzz_attribute"]  # Randomly change attribute values
+
+        # Exposed mutators
+        self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete
+
+    def __parse_xml(self, xml):
+
+        """ Parse an XML string. Basic wrapper around lxml.parse() """
+
+        try:
+            # Function parse() takes care of comments / DTD / processing instructions / ...
+            tree = ET.parse(io.BytesIO(xml))
+        except ET.ParseError:
+            raise RuntimeError("XML isn't well-formed!")
+        except LookupError as e:
+            raise RuntimeError(e)
+
+        # Return a document wrapper
+        return tree
+
+    def __exec_among(self, module, functions, min_times, max_times):
+
+        """ Randomly execute $functions between $min and $max times """
+
+        for i in xrange(random.randint(min_times, max_times)):
+            # Function names are mangled because they are "private"
+            getattr(module, "_XmlMutatorMin__" + random.choice(functions))()
+
+    def __serialize_xml(self, tree):
+
+        """ Serialize a XML document. Basic wrapper around lxml.tostring() """
+
+        return ET.tostring(
+            tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding
+        )
+
+    def __ver(self, version):
+
+        """ Helper for displaying lxml version numbers """
+
+        return ".".join(map(str, version))
+
+    def reset(self):
+
+        """ Reset the mutator """
+
+        self.tree = deepcopy(self.input_tree)
+
+    def init_from_string(self, input_string):
+
+        """ Initialize the mutator from a XML string """
+
+        # Get a pointer to the top-element
+        self.input_tree = self.__parse_xml(input_string)
+
+        # Get a working copy
+        self.tree = deepcopy(self.input_tree)
+
+    def save_to_string(self):
+
+        """ Return the current XML document as UTF-8 string """
+
+        # Return a text version of the tree
+        return self.__serialize_xml(self.tree)
+
+    def __pick_element(self, exclude_root_node=False):
+
+        """ Pick a random element from the current document """
+
+        # Get a list of all elements, but nodes like PI and comments
+        elems = list(self.tree.getroot().iter(tag=ET.Element))
+
+        # Is the root node excluded?
+        if exclude_root_node:
+            start = 1
+        else:
+            start = 0
+
+        # Pick a random element
+        try:
+            elem_id = random.randint(start, len(elems) - 1)
+            elem = elems[elem_id]
+        except ValueError:
+            # Should only occurs if "exclude_root_node = True"
+            return (None, None)
+
+        return (elem_id, elem)
+
+    def __fuzz_attribute(self):
+
+        """ Fuzz (part of) an attribute value """
+
+        # Select a node to modify
+        (rand_elem_id, rand_elem) = self.__pick_element()
+
+        # Get all the attributes
+        attribs = rand_elem.keys()
+
+        # Is there attributes?
+        if len(attribs) < 1:
+            if self.verbose:
+                print("No attribute: can't replace!")
+            return
+
+        # Pick a random attribute
+        rand_attrib_id = random.randint(0, len(attribs) - 1)
+        rand_attrib = attribs[rand_attrib_id]
+
+        # We have the attribute to modify
+        # Get its value
+        attrib_value = rand_elem.get(rand_attrib)
+        # print("- Value: " + attrib_value)
+
+        # Should we work on the whole value?
+        func_call = "(?P<func>[a-zA-Z:\-]+)\((?P<args>.*?)\)"
+        p = re.compile(func_call)
+        l = p.findall(attrib_value)
+        if random.choice((True, False)) and l:
+            # Randomly pick one the function calls
+            (func, args) = random.choice(l)
+            # Split by "," and randomly pick one of the arguments
+            value = random.choice(args.split(","))
+            # Remove superfluous characters
+            unclean_value = value
+            value = value.strip(" ").strip("'")
+            # print("Selected argument: [%s]" % value)
+        else:
+            value = attrib_value
+
+        # For each type, define some possible replacement values
+        choices_number = (
+            "0",
+            "11111",
+            "-128",
+            "2",
+            "-1",
+            "1/3",
+            "42/0",
+            "1094861636 idiv 1.0",
+            "-1123329771506872 idiv 3.8",
+            "17=$numericRTF",
+            str(3 + random.randrange(0, 100)),
+        )
+
+        choices_letter = (
+            "P" * (25 * random.randrange(1, 100)),
+            "%s%s%s%s%s%s",
+            "foobar",
+        )
+
+        choices_alnum = (
+            "Abc123",
+            "020F0302020204030204",
+            "020F0302020204030204" * (random.randrange(5, 20)),
+        )
+
+        # Fuzz the value
+        if random.choice((True, False)) and value == "":
+
+            # Empty
+            new_value = value
+
+        elif random.choice((True, False)) and value.isdigit():
+
+            # Numbers
+            new_value = random.choice(choices_number)
+
+        elif random.choice((True, False)) and value.isalpha():
+
+            # Letters
+            new_value = random.choice(choices_letter)
+
+        elif random.choice((True, False)) and value.isalnum():
+
+            # Alphanumeric
+            new_value = random.choice(choices_alnum)
+
+        else:
+
+            # Default type
+            new_value = random.choice(choices_alnum + choices_letter + choices_number)
+
+        # If we worked on a substring, apply changes to the whole string
+        if value != attrib_value:
+            # No ' around empty values
+            if new_value != "" and value != "":
+                new_value = "'" + new_value + "'"
+            # Apply changes
+            new_value = attrib_value.replace(unclean_value, new_value)
+
+        # Log something
+        if self.verbose:
+            print(
+                "Fuzzing attribute #%i '%s' of tag #%i '%s'"
+                % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
+            )
+
+        # Modify the attribute
+        rand_elem.set(rand_attrib, new_value.decode("utf-8"))
+
+    def __del_node_and_children(self):
+
+        """High-level minimizing mutator
+        Delete a random node and its children (i.e. delete a random tree)"""
+
+        self.__del_node(True)
+
+    def __del_node_but_children(self):
+
+        """High-level minimizing mutator
+        Delete a random node but its children (i.e. link them to the parent of the deleted node)"""
+
+        self.__del_node(False)
+
+    def __del_node(self, delete_children):
+
+        """ Called by the __del_node_* mutators """
+
+        # Select a node to modify (but the root one)
+        (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True)
+
+        # If the document includes only a top-level element
+        # Then we can't pick a element (given that "exclude_root_node = True")
+
+        # Is the document deep enough?
+        if rand_elem is None:
+            if self.verbose:
+                print("Can't delete a node: document not deep enough!")
+            return
+
+        # Log something
+        if self.verbose:
+            but_or_and = "and" if delete_children else "but"
+            print(
+                "Deleting tag #%i '%s' %s its children"
+                % (rand_elem_id, rand_elem.tag, but_or_and)
+            )
+
+        if delete_children is False:
+            # Link children of the random (soon to be deleted) node to its parent
+            for child in rand_elem:
+                rand_elem.getparent().append(child)
+
+        # Remove the node
+        rand_elem.getparent().remove(rand_elem)
+
+    def __del_content(self):
+
+        """High-level minimizing mutator
+        Delete the attributes and children of a random node"""
+
+        # Select a node to modify
+        (rand_elem_id, rand_elem) = self.__pick_element()
+
+        # Log something
+        if self.verbose:
+            print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
+
+        # Reset the node
+        rand_elem.clear()
+
+    def __del_attribute(self):
+
+        """High-level minimizing mutator
+        Delete a random attribute from a random node"""
+
+        # Select a node to modify
+        (rand_elem_id, rand_elem) = self.__pick_element()
+
+        # Get all the attributes
+        attribs = rand_elem.keys()
+
+        # Is there attributes?
+        if len(attribs) < 1:
+            if self.verbose:
+                print("No attribute: can't delete!")
+            return
+
+        # Pick a random attribute
+        rand_attrib_id = random.randint(0, len(attribs) - 1)
+        rand_attrib = attribs[rand_attrib_id]
+
+        # Log something
+        if self.verbose:
+            print(
+                "Deleting attribute #%i '%s' of tag #%i '%s'"
+                % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag)
+            )
+
+        # Delete the attribute
+        rand_elem.attrib.pop(rand_attrib)
+
+    def mutate(self, min=1, max=5):
+
+        """ Execute some high-level mutators between $min and $max times, then some medium-level ones """
+
+        # High-level mutation
+        self.__exec_among(self, self.hl_mutators_all, min, max)
diff --git a/utils/custom_mutators/common.py b/utils/custom_mutators/common.py
new file mode 100644
index 00000000..44a5056a
--- /dev/null
+++ b/utils/custom_mutators/common.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Module containing functions shared between multiple AFL modules
+
+@author:     Christian Holler (:decoder)
+
+@license:
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+@contact:    choller@mozilla.com
+"""
+
+from __future__ import print_function
+import random
+import os
+import re
+
+
+def randel(l):
+    if not l:
+        return None
+    return l[random.randint(0, len(l) - 1)]
+
+
+def randel_pop(l):
+    if not l:
+        return None
+    return l.pop(random.randint(0, len(l) - 1))
+
+
+def write_exc_example(data, exc):
+    exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc))
+
+    if not os.path.exists(exc_name):
+        with open(exc_name, "w") as f:
+            f.write(data)
diff --git a/utils/custom_mutators/custom_mutator_helpers.h b/utils/custom_mutators/custom_mutator_helpers.h
new file mode 100644
index 00000000..62e6efba
--- /dev/null
+++ b/utils/custom_mutators/custom_mutator_helpers.h
@@ -0,0 +1,342 @@
+#ifndef CUSTOM_MUTATOR_HELPERS
+#define CUSTOM_MUTATOR_HELPERS
+
+#include "config.h"
+#include "types.h"
+#include <stdlib.h>
+
+#define INITIAL_GROWTH_SIZE (64)
+
+#define RAND_BELOW(limit) (rand() % (limit))
+
+/* Use in a struct: creates a name_buf and a name_size variable. */
+#define BUF_VAR(type, name) \
+  type * name##_buf;        \
+  size_t name##_size;
+/* this fills in `&structptr->something_buf, &structptr->something_size`. */
+#define BUF_PARAMS(struct, name) \
+  (void **)&struct->name##_buf, &struct->name##_size
+
+typedef struct {
+
+} afl_t;
+
+static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
+
+  static s8  interesting_8[] = {INTERESTING_8};
+  static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
+  static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
+
+  switch (RAND_BELOW(12)) {
+
+    case 0: {
+
+      /* Flip a single bit somewhere. Spooky! */
+
+      s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
+
+      out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
+
+      break;
+
+    }
+
+    case 1: {
+
+      /* Set byte to interesting value. */
+
+      u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
+      out_buf[(RAND_BELOW(end - begin) + begin)] = val;
+
+      break;
+
+    }
+
+    case 2: {
+
+      /* Set word to interesting value, randomly choosing endian. */
+
+      if (end - begin < 2) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 1) break;
+
+      switch (RAND_BELOW(2)) {
+
+        case 0:
+          *(u16 *)(out_buf + byte_idx) =
+              interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
+          break;
+        case 1:
+          *(u16 *)(out_buf + byte_idx) =
+              SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
+          break;
+
+      }
+
+      break;
+
+    }
+
+    case 3: {
+
+      /* Set dword to interesting value, randomly choosing endian. */
+
+      if (end - begin < 4) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 3) break;
+
+      switch (RAND_BELOW(2)) {
+
+        case 0:
+          *(u32 *)(out_buf + byte_idx) =
+              interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
+          break;
+        case 1:
+          *(u32 *)(out_buf + byte_idx) =
+              SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
+          break;
+
+      }
+
+      break;
+
+    }
+
+    case 4: {
+
+      /* Set qword to interesting value, randomly choosing endian. */
+
+      if (end - begin < 8) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 7) break;
+
+      switch (RAND_BELOW(2)) {
+
+        case 0:
+          *(u64 *)(out_buf + byte_idx) =
+              (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
+          break;
+        case 1:
+          *(u64 *)(out_buf + byte_idx) = SWAP64(
+              (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
+          break;
+
+      }
+
+      break;
+
+    }
+
+    case 5: {
+
+      /* Randomly subtract from byte. */
+
+      out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
+
+      break;
+
+    }
+
+    case 6: {
+
+      /* Randomly add to byte. */
+
+      out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
+
+      break;
+
+    }
+
+    case 7: {
+
+      /* Randomly subtract from word, random endian. */
+
+      if (end - begin < 2) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 1) break;
+
+      if (RAND_BELOW(2)) {
+
+        *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
+
+      } else {
+
+        u16 num = 1 + RAND_BELOW(ARITH_MAX);
+
+        *(u16 *)(out_buf + byte_idx) =
+            SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
+
+      }
+
+      break;
+
+    }
+
+    case 8: {
+
+      /* Randomly add to word, random endian. */
+
+      if (end - begin < 2) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 1) break;
+
+      if (RAND_BELOW(2)) {
+
+        *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
+
+      } else {
+
+        u16 num = 1 + RAND_BELOW(ARITH_MAX);
+
+        *(u16 *)(out_buf + byte_idx) =
+            SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
+
+      }
+
+      break;
+
+    }
+
+    case 9: {
+
+      /* Randomly subtract from dword, random endian. */
+
+      if (end - begin < 4) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 3) break;
+
+      if (RAND_BELOW(2)) {
+
+        *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
+
+      } else {
+
+        u32 num = 1 + RAND_BELOW(ARITH_MAX);
+
+        *(u32 *)(out_buf + byte_idx) =
+            SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
+
+      }
+
+      break;
+
+    }
+
+    case 10: {
+
+      /* Randomly add to dword, random endian. */
+
+      if (end - begin < 4) break;
+
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
+
+      if (byte_idx >= end - 3) break;
+
+      if (RAND_BELOW(2)) {
+
+        *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
+
+      } else {
+
+        u32 num = 1 + RAND_BELOW(ARITH_MAX);
+
+        *(u32 *)(out_buf + byte_idx) =
+            SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
+
+      }
+
+      break;
+
+    }
+
+    case 11: {
+
+      /* Just set a random byte to a random value. Because,
+         why not. We use XOR with 1-255 to eliminate the
+         possibility of a no-op. */
+
+      out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
+
+      break;
+
+    }
+
+  }
+
+}
+
+/* This function calculates the next power of 2 greater or equal its argument.
+ @return The rounded up power of 2 (if no overflow) or 0 on overflow.
+*/
+static inline size_t next_pow2(size_t in) {
+
+  if (in == 0 || in > (size_t)-1)
+    return 0;                  /* avoid undefined behaviour under-/overflow */
+  size_t out = in - 1;
+  out |= out >> 1;
+  out |= out >> 2;
+  out |= out >> 4;
+  out |= out >> 8;
+  out |= out >> 16;
+  return out + 1;
+
+}
+
+/* This function makes sure *size is > size_needed after call.
+ It will realloc *buf otherwise.
+ *size will grow exponentially as per:
+ https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
+ Will return NULL and free *buf if size_needed is <1 or realloc failed.
+ @return For convenience, this function returns *buf.
+ */
+static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
+
+  /* No need to realloc */
+  if (likely(size_needed && *size >= size_needed)) return *buf;
+
+  /* No initial size was set */
+  if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
+
+  /* grow exponentially */
+  size_t next_size = next_pow2(size_needed);
+
+  /* handle overflow */
+  if (!next_size) { next_size = size_needed; }
+
+  /* alloc */
+  *buf = realloc(*buf, next_size);
+  *size = *buf ? next_size : 0;
+
+  return *buf;
+
+}
+
+/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
+static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
+                                 size_t *size2) {
+
+  void * scratch_buf = *buf1;
+  size_t scratch_size = *size1;
+  *buf1 = *buf2;
+  *size1 = *size2;
+  *buf2 = scratch_buf;
+  *size2 = scratch_size;
+
+}
+
+#undef INITIAL_GROWTH_SIZE
+
+#endif
+
diff --git a/utils/custom_mutators/example.c b/utils/custom_mutators/example.c
new file mode 100644
index 00000000..23add128
--- /dev/null
+++ b/utils/custom_mutators/example.c
@@ -0,0 +1,376 @@
+/*
+  New Custom Mutator for AFL++
+  Written by Khaled Yakdan <yakdan@code-intelligence.de>
+             Andrea Fioraldi <andreafioraldi@gmail.com>
+             Shengtuo Hu <h1994st@gmail.com>
+             Dominik Maier <mail@dmnk.co>
+*/
+
+// You need to use -I /path/to/AFLplusplus/include
+#include "custom_mutator_helpers.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define DATA_SIZE (100)
+
+static const char *commands[] = {
+
+    "GET",
+    "PUT",
+    "DEL",
+
+};
+
+typedef struct my_mutator {
+
+  afl_t *afl;
+
+  // any additional data here!
+  size_t trim_size_current;
+  int    trimmming_steps;
+  int    cur_step;
+
+  // Reused buffers:
+  BUF_VAR(u8, fuzz);
+  BUF_VAR(u8, data);
+  BUF_VAR(u8, havoc);
+  BUF_VAR(u8, trim);
+  BUF_VAR(u8, post_process);
+
+} my_mutator_t;
+
+/**
+ * Initialize this custom mutator
+ *
+ * @param[in] afl a pointer to the internal state object. Can be ignored for
+ * now.
+ * @param[in] seed A seed for this mutator - the same seed should always mutate
+ * in the same way.
+ * @return Pointer to the data object this custom mutator instance should use.
+ *         There may be multiple instances of this mutator in one afl-fuzz run!
+ *         Return NULL on error.
+ */
+my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+
+  srand(seed);  // needed also by surgical_havoc_mutate()
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  data->afl = afl;
+
+  return data;
+
+}
+
+/**
+ * Perform custom mutations on a given input
+ *
+ * (Optional for now. Required in the future)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Pointer to input data to be mutated
+ * @param[in] buf_size Size of input data
+ * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
+ * error.
+ * @param[in] add_buf Buffer containing the additional test case
+ * @param[in] add_buf_size Size of the additional test case
+ * @param[in] max_size Maximum size of the mutated output. The mutation must not
+ *     produce data larger than max_size.
+ * @return Size of the mutated output.
+ */
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
+                       u8 **out_buf, uint8_t *add_buf,
+                       size_t add_buf_size,  // add_buf can be NULL
+                       size_t max_size) {
+
+  // Make sure that the packet size does not exceed the maximum size expected by
+  // the fuzzer
+  size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
+
+  // maybe_grow is optimized to be quick for reused buffers.
+  u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
+  if (!mutated_out) {
+
+    *out_buf = NULL;
+    perror("custom mutator allocation (maybe_grow)");
+    return 0;            /* afl-fuzz will very likely error out after this. */
+
+  }
+
+  // Randomly select a command string to add as a header to the packet
+  memcpy(mutated_out, commands[rand() % 3], 3);
+
+  // Mutate the payload of the packet
+  int i;
+  for (i = 0; i < 8; ++i) {
+
+    // Randomly perform one of the (no len modification) havoc mutations
+    surgical_havoc_mutate(mutated_out, 3, mutated_size);
+
+  }
+
+  *out_buf = mutated_out;
+  return mutated_size;
+
+}
+
+/**
+ * A post-processing function to use right before AFL writes the test case to
+ * disk in order to execute the target.
+ *
+ * (Optional) If this functionality is not needed, simply don't define this
+ * function.
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Buffer containing the test case to be executed
+ * @param[in] buf_size Size of the test case
+ * @param[out] out_buf Pointer to the buffer containing the test case after
+ *     processing. External library should allocate memory for out_buf.
+ *     The buf pointer may be reused (up to the given buf_size);
+ * @return Size of the output buffer after processing or the needed amount.
+ *     A return of 0 indicates an error.
+ */
+size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
+                               size_t buf_size, uint8_t **out_buf) {
+
+  uint8_t *post_process_buf =
+      maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
+  if (!post_process_buf) {
+
+    perror("custom mutator realloc failed.");
+    *out_buf = NULL;
+    return 0;
+
+  }
+
+  memcpy(post_process_buf + 5, buf, buf_size);
+  post_process_buf[0] = 'A';
+  post_process_buf[1] = 'F';
+  post_process_buf[2] = 'L';
+  post_process_buf[3] = '+';
+  post_process_buf[4] = '+';
+
+  *out_buf = post_process_buf;
+
+  return buf_size + 5;
+
+}
+
+/**
+ * This method is called at the start of each trimming operation and receives
+ * the initial buffer. It should return the amount of iteration steps possible
+ * on this input (e.g. if your input has n elements and you want to remove
+ * them one by one, return n, if you do a binary search, return log(n),
+ * and so on...).
+ *
+ * If your trimming algorithm doesn't allow you to determine the amount of
+ * (remaining) steps easily (esp. while running), then you can alternatively
+ * return 1 here and always return 0 in post_trim until you are finished and
+ * no steps remain. In that case, returning 1 in post_trim will end the
+ * trimming routine. The whole current index/max iterations stuff is only used
+ * to show progress.
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init for this fuzz case
+ * @param buf Buffer containing the test case
+ * @param buf_size Size of the test case
+ * @return The amount of possible iteration steps to trim the input.
+ *        negative on error.
+ */
+int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
+                             size_t buf_size) {
+
+  // We simply trim once
+  data->trimmming_steps = 1;
+
+  data->cur_step = 0;
+
+  if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
+
+    perror("init_trim grow");
+    return -1;
+
+  }
+
+  memcpy(data->trim_buf, buf, buf_size);
+
+  data->trim_size_current = buf_size;
+
+  return data->trimmming_steps;
+
+}
+
+/**
+ * This method is called for each trimming operation. It doesn't have any
+ * arguments because we already have the initial buffer from init_trim and we
+ * can memorize the current state in *data. This can also save
+ * reparsing steps for each iteration. It should return the trimmed input
+ * buffer, where the returned data must not exceed the initial input data in
+ * length. Returning anything that is larger than the original data (passed
+ * to init_trim) will result in a fatal abort of AFLFuzz.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
+ *     External library should allocate memory for out_buf.
+ *     AFL++ will not release the memory after saving the test case.
+ *     Keep a ref in *data.
+ *     *out_buf = NULL is treated as error.
+ * @return Pointer to the size of the trimmed test case
+ */
+size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) {
+
+  *out_buf = data->trim_buf;
+
+  // Remove the last byte of the trimming input
+  return data->trim_size_current - 1;
+
+}
+
+/**
+ * This method is called after each trim operation to inform you if your
+ * trimming step was successful or not (in terms of coverage). If you receive
+ * a failure here, you should reset your input to the last known good state.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param success Indicates if the last trim operation was successful.
+ * @return The next trim iteration index (from 0 to the maximum amount of
+ *     steps returned in init_trim). negative ret on failure.
+ */
+int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
+
+  if (success) {
+
+    ++data->cur_step;
+    return data->cur_step;
+
+  }
+
+  return data->trimmming_steps;
+
+}
+
+/**
+ * Perform a single custom mutation on a given input.
+ * This mutation is stacked with the other muatations in havoc.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Pointer to the input data to be mutated and the mutated
+ *     output
+ * @param[in] buf_size Size of input data
+ * @param[out] out_buf The output buffer. buf can be reused, if the content
+ * fits. *out_buf = NULL is treated as error.
+ * @param[in] max_size Maximum size of the mutated output. The mutation must
+ *     not produce data larger than max_size.
+ * @return Size of the mutated output.
+ */
+size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
+                                 u8 **out_buf, size_t max_size) {
+
+  if (buf_size == 0) {
+
+    *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
+    if (!*out_buf) {
+
+      perror("custom havoc: maybe_grow");
+      return 0;
+
+    }
+
+    **out_buf = rand() % 256;
+    buf_size = 1;
+
+  } else {
+
+    // We reuse buf here. It's legal and faster.
+    *out_buf = buf;
+
+  }
+
+  size_t victim = rand() % buf_size;
+  (*out_buf)[victim] += rand() % 10;
+
+  return buf_size;
+
+}
+
+/**
+ * Return the probability (in percentage) that afl_custom_havoc_mutation
+ * is called in havoc. By default it is 6 %.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @return The probability (0-100).
+ */
+uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
+
+  return 5;  // 5 %
+
+}
+
+/**
+ * Determine whether the fuzzer should fuzz the queue entry or not.
+ *
+ * (Optional)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param filename File name of the test case in the queue entry
+ * @return Return True(1) if the fuzzer will fuzz the queue entry, and
+ *     False(0) otherwise.
+ */
+uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
+
+  return 1;
+
+}
+
+/**
+ * Allow for additional analysis (e.g. calling a different tool that does a
+ * different kind of coverage and saves this for the custom mutator).
+ *
+ * (Optional)
+ *
+ * @param data pointer returned in afl_custom_init for this fuzz case
+ * @param filename_new_queue File name of the new queue entry
+ * @param filename_orig_queue File name of the original queue entry
+ */
+void afl_custom_queue_new_entry(my_mutator_t * data,
+                                const uint8_t *filename_new_queue,
+                                const uint8_t *filename_orig_queue) {
+
+  /* Additional analysis on the original or new test case */
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->post_process_buf);
+  free(data->havoc_buf);
+  free(data->data_buf);
+  free(data->fuzz_buf);
+  free(data->trim_buf);
+  free(data);
+
+}
+
diff --git a/utils/custom_mutators/example.py b/utils/custom_mutators/example.py
new file mode 100644
index 00000000..3a6d22e4
--- /dev/null
+++ b/utils/custom_mutators/example.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Example Python Module for AFLFuzz
+
+@author:     Christian Holler (:decoder)
+
+@license:
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+@contact:    choller@mozilla.com
+"""
+
+import random
+
+
+COMMANDS = [
+    b"GET",
+    b"PUT",
+    b"DEL",
+    b"AAAAAAAAAAAAAAAAA",
+]
+
+
+def init(seed):
+    """
+    Called once when AFLFuzz starts up. Used to seed our RNG.
+
+    @type seed: int
+    @param seed: A 32-bit random value
+    """
+    random.seed(seed)
+
+
+def deinit():
+    pass
+
+
+def fuzz(buf, add_buf, max_size):
+    """
+    Called per fuzzing iteration.
+
+    @type buf: bytearray
+    @param buf: The buffer that should be mutated.
+
+    @type add_buf: bytearray
+    @param add_buf: A second buffer that can be used as mutation source.
+
+    @type max_size: int
+    @param max_size: Maximum size of the mutated output. The mutation must not
+        produce data larger than max_size.
+
+    @rtype: bytearray
+    @return: A new bytearray containing the mutated data
+    """
+    ret = bytearray(100)
+
+    ret[:3] = random.choice(COMMANDS)
+
+    return ret
+
+
+# Uncomment and implement the following methods if you want to use a custom
+# trimming algorithm. See also the documentation for a better API description.
+
+# def init_trim(buf):
+#     '''
+#     Called per trimming iteration.
+#
+#     @type buf: bytearray
+#     @param buf: The buffer that should be trimmed.
+#
+#     @rtype: int
+#     @return: The maximum number of trimming steps.
+#     '''
+#     global ...
+#
+#     # Initialize global variables
+#
+#     # Figure out how many trimming steps are possible.
+#     # If this is not possible for your trimming, you can
+#     # return 1 instead and always return 0 in post_trim
+#     # until you are done (then you return 1).
+#
+#     return steps
+#
+# def trim():
+#     '''
+#     Called per trimming iteration.
+#
+#     @rtype: bytearray
+#     @return: A new bytearray containing the trimmed data.
+#     '''
+#     global ...
+#
+#     # Implement the actual trimming here
+#
+#     return bytearray(...)
+#
+# def post_trim(success):
+#     '''
+#     Called after each trimming operation.
+#
+#     @type success: bool
+#     @param success: Indicates if the last trim operation was successful.
+#
+#     @rtype: int
+#     @return: The next trim index (0 to max number of steps) where max
+#              number of steps indicates the trimming is done.
+#     '''
+#     global ...
+#
+#     if not success:
+#         # Restore last known successful input, determine next index
+#     else:
+#         # Just determine the next index, based on what was successfully
+#         # removed in the last step
+#
+#     return next_index
+#
+# def post_process(buf):
+#     '''
+#     Called just before the execution to write the test case in the format
+#     expected by the target
+#
+#     @type buf: bytearray
+#     @param buf: The buffer containing the test case to be executed
+#
+#     @rtype: bytearray
+#     @return: The buffer containing the test case after
+#     '''
+#     return buf
+#
+# def havoc_mutation(buf, max_size):
+#     '''
+#     Perform a single custom mutation on a given input.
+#
+#     @type buf: bytearray
+#     @param buf: The buffer that should be mutated.
+#
+#     @type max_size: int
+#     @param max_size: Maximum size of the mutated output. The mutation must not
+#         produce data larger than max_size.
+#
+#     @rtype: bytearray
+#     @return: A new bytearray containing the mutated data
+#     '''
+#     return mutated_buf
+#
+# def havoc_mutation_probability():
+#     '''
+#     Called for each `havoc_mutation`. Return the probability (in percentage)
+#     that `havoc_mutation` is called in havoc. Be default it is 6%.
+#
+#     @rtype: int
+#     @return: The probability (0-100)
+#     '''
+#     return prob
+#
+# def queue_get(filename):
+#     '''
+#     Called at the beginning of each fuzz iteration to determine whether the
+#     test case should be fuzzed
+#
+#     @type filename: str
+#     @param filename: File name of the test case in the current queue entry
+#
+#     @rtype: bool
+#     @return: Return True if the custom mutator decides to fuzz the test case,
+#         and False otherwise
+#     '''
+#     return True
+#
+# def queue_new_entry(filename_new_queue, filename_orig_queue):
+#     '''
+#     Called after adding a new test case to the queue
+#
+#     @type filename_new_queue: str
+#     @param filename_new_queue: File name of the new queue entry
+#
+#     @type filename_orig_queue: str
+#     @param filename_orig_queue: File name of the original queue entry
+#     '''
+#     pass
diff --git a/utils/custom_mutators/post_library_gif.so.c b/utils/custom_mutators/post_library_gif.so.c
new file mode 100644
index 00000000..ac10f409
--- /dev/null
+++ b/utils/custom_mutators/post_library_gif.so.c
@@ -0,0 +1,165 @@
+/*
+   american fuzzy lop++ - postprocessor library example
+   --------------------------------------------------
+
+   Originally written by Michal Zalewski
+   Edited by Dominik Maier, 2020
+
+   Copyright 2015 Google Inc. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   Postprocessor libraries can be passed to afl-fuzz to perform final cleanup
+   of any mutated test cases - for example, to fix up checksums in PNG files.
+
+   Please heed the following warnings:
+
+   1) In almost all cases, it is more productive to comment out checksum logic
+      in the targeted binary (as shown in ../libpng_no_checksum/). One possible
+      exception is the process of fuzzing binary-only software in QEMU mode.
+
+   2) The use of postprocessors for anything other than checksums is
+   questionable and may cause more harm than good. AFL is normally pretty good
+   about dealing with length fields, magic values, etc.
+
+   3) Postprocessors that do anything non-trivial must be extremely robust to
+      gracefully handle malformed data and other error conditions - otherwise,
+      they will crash and take afl-fuzz down with them. Be wary of reading past
+      *len and of integer overflows when calculating file offsets.
+
+   In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really,
+   honestly know what you're doing =)
+
+   With that out of the way: the postprocessor library is passed to afl-fuzz
+   via AFL_POST_LIBRARY. The library must be compiled with:
+
+     gcc -shared -Wall -O3 post_library.so.c -o post_library.so
+
+   AFL will call the afl_custom_post_process() function for every mutated output
+   buffer. From there, you have three choices:
+
+   1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
+      and return the original `len`.
+
+   2) If you want to skip this test case altogether and have AFL generate a
+      new one, return 0 or set `*out_buf = NULL`.
+      Use this sparingly - it's faster than running the target program
+      with patently useless inputs, but still wastes CPU time.
+
+   3) If you want to modify the test case, allocate an appropriately-sized
+      buffer, move the data into that buffer, make the necessary changes, and
+      then return the new pointer as out_buf. Return an appropriate len
+   afterwards.
+
+      Note that the buffer will *not* be freed for you. To avoid memory leaks,
+      you need to free it or reuse it on subsequent calls (as shown below).
+
+      *** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
+
+    Aight. The example below shows a simple postprocessor that tries to make
+    sure that all input files start with "GIF89a".
+
+    PS. If you don't like C, you can try out the unix-based wrapper from
+    Ben Nagy instead: https://github.com/bnagy/aflfix
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Header that must be present at the beginning of every test case: */
+
+#define HEADER "GIF89a"
+
+typedef struct post_state {
+
+  unsigned char *buf;
+  size_t         size;
+
+} post_state_t;
+
+void *afl_custom_init(void *afl) {
+
+  post_state_t *state = malloc(sizeof(post_state_t));
+  if (!state) {
+
+    perror("malloc");
+    return NULL;
+
+  }
+
+  state->buf = calloc(sizeof(unsigned char), 4096);
+  if (!state->buf) {
+
+    free(state);
+    perror("calloc");
+    return NULL;
+
+  }
+
+  return state;
+
+}
+
+/* The actual postprocessor routine called by afl-fuzz: */
+
+size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
+                               unsigned int len, unsigned char **out_buf) {
+
+  /* Skip execution altogether for buffers shorter than 6 bytes (just to
+     show how it's done). We can trust len to be sane. */
+
+  if (len < strlen(HEADER)) return 0;
+
+  /* Do nothing for buffers that already start with the expected header. */
+
+  if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
+
+    *out_buf = in_buf;
+    return len;
+
+  }
+
+  /* Allocate memory for new buffer, reusing previous allocation if
+     possible. */
+
+  *out_buf = realloc(data->buf, len);
+
+  /* If we're out of memory, the most graceful thing to do is to return the
+     original buffer and give up on modifying it. Let AFL handle OOM on its
+     own later on. */
+
+  if (!*out_buf) {
+
+    *out_buf = in_buf;
+    return len;
+
+  }
+
+  /* Copy the original data to the new location. */
+
+  memcpy(*out_buf, in_buf, len);
+
+  /* Insert the new header. */
+
+  memcpy(*out_buf, HEADER, strlen(HEADER));
+
+  /* Return the new len. It hasn't changed, so it's just len. */
+
+  return len;
+
+}
+
+/* Gets called afterwards */
+void afl_custom_deinit(post_state_t *data) {
+
+  free(data->buf);
+  free(data);
+
+}
+
diff --git a/utils/custom_mutators/post_library_png.so.c b/utils/custom_mutators/post_library_png.so.c
new file mode 100644
index 00000000..941f7e55
--- /dev/null
+++ b/utils/custom_mutators/post_library_png.so.c
@@ -0,0 +1,163 @@
+/*
+   american fuzzy lop++ - postprocessor for PNG
+   ------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2015 Google Inc. All rights reserved.
+   Adapted to the new API, 2020 by Dominik Maier
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   See post_library.so.c for a general discussion of how to implement
+   postprocessors. This specific postprocessor attempts to fix up PNG
+   checksums, providing a slightly more complicated example than found
+   in post_library.so.c.
+
+   Compile with:
+
+     gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <zlib.h>
+
+#include <arpa/inet.h>
+
+/* A macro to round an integer up to 4 kB. */
+
+#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
+
+typedef struct post_state {
+
+  unsigned char *buf;
+  size_t         size;
+
+} post_state_t;
+
+void *afl_custom_init(void *afl) {
+
+  post_state_t *state = malloc(sizeof(post_state_t));
+  if (!state) {
+
+    perror("malloc");
+    return NULL;
+
+  }
+
+  state->buf = calloc(sizeof(unsigned char), 4096);
+  if (!state->buf) {
+
+    free(state);
+    perror("calloc");
+    return NULL;
+
+  }
+
+  return state;
+
+}
+
+size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
+                               unsigned int          len,
+                               const unsigned char **out_buf) {
+
+  unsigned char *new_buf = (unsigned char *)in_buf;
+  unsigned int   pos = 8;
+
+  /* Don't do anything if there's not enough room for the PNG header
+     (8 bytes). */
+
+  if (len < 8) {
+
+    *out_buf = in_buf;
+    return len;
+
+  }
+
+  /* Minimum size of a zero-length PNG chunk is 12 bytes; if we
+     don't have that, we can bail out. */
+
+  while (pos + 12 <= len) {
+
+    unsigned int chunk_len, real_cksum, file_cksum;
+
+    /* Chunk length is the first big-endian dword in the chunk. */
+
+    chunk_len = ntohl(*(uint32_t *)(in_buf + pos));
+
+    /* Bail out if chunk size is too big or goes past EOF. */
+
+    if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
+
+    /* Chunk checksum is calculated for chunk ID (dword) and the actual
+       payload. */
+
+    real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4));
+
+    /* The in-file checksum is the last dword past the chunk data. */
+
+    file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len);
+
+    /* If the checksums do not match, we need to fix the file. */
+
+    if (real_cksum != file_cksum) {
+
+      /* First modification? Make a copy of the input buffer. Round size
+         up to 4 kB to minimize the number of reallocs needed. */
+
+      if (new_buf == in_buf) {
+
+        if (len <= data->size) {
+
+          new_buf = data->buf;
+
+        } else {
+
+          new_buf = realloc(data->buf, UP4K(len));
+          if (!new_buf) {
+
+            *out_buf = in_buf;
+            return len;
+
+          }
+
+          data->buf = new_buf;
+          data->size = UP4K(len);
+          memcpy(new_buf, in_buf, len);
+
+        }
+
+      }
+
+      *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
+
+    }
+
+    /* Skip the entire chunk and move to the next one. */
+
+    pos += 12 + chunk_len;
+
+  }
+
+  *out_buf = new_buf;
+  return len;
+
+}
+
+/* Gets called afterwards */
+void afl_custom_deinit(post_state_t *data) {
+
+  free(data->buf);
+  free(data);
+
+}
+
diff --git a/utils/custom_mutators/simple-chunk-replace.py b/utils/custom_mutators/simple-chunk-replace.py
new file mode 100644
index 00000000..c57218dd
--- /dev/null
+++ b/utils/custom_mutators/simple-chunk-replace.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Simple Chunk Cross-Over Replacement Module for AFLFuzz
+
+@author:     Christian Holler (:decoder)
+
+@license:
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+@contact:    choller@mozilla.com
+"""
+
+import random
+
+
+def init(seed):
+    """
+    Called once when AFLFuzz starts up. Used to seed our RNG.
+
+    @type seed: int
+    @param seed: A 32-bit random value
+    """
+    # Seed our RNG
+    random.seed(seed)
+
+
+def fuzz(buf, add_buf, max_size):
+    """
+    Called per fuzzing iteration.
+
+    @type buf: bytearray
+    @param buf: The buffer that should be mutated.
+
+    @type add_buf: bytearray
+    @param add_buf: A second buffer that can be used as mutation source.
+
+    @type max_size: int
+    @param max_size: Maximum size of the mutated output. The mutation must not
+        produce data larger than max_size.
+
+    @rtype: bytearray
+    @return: A new bytearray containing the mutated data
+    """
+    # Make a copy of our input buffer for returning
+    ret = bytearray(buf)
+
+    # Take a random fragment length between 2 and 32 (or less if add_buf is shorter)
+    fragment_len = random.randint(1, min(len(add_buf), 32))
+
+    # Determine a random source index where to take the data chunk from
+    rand_src_idx = random.randint(0, len(add_buf) - fragment_len)
+
+    # Determine a random destination index where to put the data chunk
+    rand_dst_idx = random.randint(0, len(buf))
+
+    # Make the chunk replacement
+    ret[rand_dst_idx : rand_dst_idx + fragment_len] = add_buf[
+        rand_src_idx : rand_src_idx + fragment_len
+    ]
+
+    # Return data
+    return ret
diff --git a/utils/custom_mutators/simple_example.c b/utils/custom_mutators/simple_example.c
new file mode 100644
index 00000000..d888ec1f
--- /dev/null
+++ b/utils/custom_mutators/simple_example.c
@@ -0,0 +1,74 @@
+// This simple example just creates random buffer <= 100 filled with 'A'
+// needs -I /path/to/AFLplusplus/include
+#include "custom_mutator_helpers.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef _FIXED_CHAR
+  #define _FIXED_CHAR 0x41
+#endif
+
+typedef struct my_mutator {
+
+  afl_t *afl;
+
+  // Reused buffers:
+  BUF_VAR(u8, fuzz);
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+
+  srand(seed);
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  data->afl = afl;
+
+  return data;
+
+}
+
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
+                       u8 **out_buf, uint8_t *add_buf,
+                       size_t add_buf_size,  // add_buf can be NULL
+                       size_t max_size) {
+
+  int size = (rand() % 100) + 1;
+  if (size > max_size) size = max_size;
+  u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
+  if (!mutated_out) {
+
+    *out_buf = NULL;
+    perror("custom mutator allocation (maybe_grow)");
+    return 0;            /* afl-fuzz will very likely error out after this. */
+
+  }
+
+  memset(mutated_out, _FIXED_CHAR, size);
+
+  *out_buf = mutated_out;
+  return size;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->fuzz_buf);
+  free(data);
+
+}
+
diff --git a/utils/custom_mutators/wrapper_afl_min.py b/utils/custom_mutators/wrapper_afl_min.py
new file mode 100644
index 00000000..5cd60031
--- /dev/null
+++ b/utils/custom_mutators/wrapper_afl_min.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+from XmlMutatorMin import XmlMutatorMin
+
+# Default settings (production mode)
+
+__mutator__ = None
+__seed__ = "RANDOM"
+__log__ = False
+__log_file__ = "wrapper.log"
+
+
+# AFL functions
+def log(text):
+    """
+    Logger
+    """
+
+    global __seed__
+    global __log__
+    global __log_file__
+
+    if __log__:
+        with open(__log_file__, "a") as logf:
+            logf.write("[%s] %s\n" % (__seed__, text))
+
+
+def init(seed):
+    """
+    Called once when AFL starts up. Seed is used to identify the AFL instance in log files
+    """
+
+    global __mutator__
+    global __seed__
+
+    # Get the seed
+    __seed__ = seed
+
+    # Create a global mutation class
+    try:
+        __mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
+        log("init(): Mutator created")
+    except RuntimeError as e:
+        log("init(): Can't create mutator: %s" % e.message)
+
+
+def fuzz(buf, add_buf, max_size):
+    """
+    Called for each fuzzing iteration.
+    """
+
+    global __mutator__
+
+    # Do we have a working mutator object?
+    if __mutator__ is None:
+        log("fuzz(): Can't fuzz, no mutator available")
+        return buf
+
+    # Try to use the AFL buffer
+    via_buffer = True
+
+    # Interpret the AFL buffer (an array of bytes) as a string
+    if via_buffer:
+        try:
+            buf_str = str(buf)
+            log("fuzz(): AFL buffer converted to a string")
+        except Exception:
+            via_buffer = False
+            log("fuzz(): Can't convert AFL buffer to a string")
+
+    # Load XML from the AFL string
+    if via_buffer:
+        try:
+            __mutator__.init_from_string(buf_str)
+            log(
+                "fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)"
+                % len(buf_str)
+            )
+        except Exception:
+            via_buffer = False
+            log("fuzz(): Can't initialize mutator with AFL buffer")
+
+    # If init from AFL buffer wasn't succesful
+    if not via_buffer:
+        log("fuzz(): Returning unmodified AFL buffer")
+        return buf
+
+    # Sucessful initialization -> mutate
+    try:
+        __mutator__.mutate(max=5)
+        log("fuzz(): Input mutated")
+    except Exception:
+        log("fuzz(): Can't mutate input => returning buf")
+        return buf
+
+    # Convert mutated data to a array of bytes
+    try:
+        data = bytearray(__mutator__.save_to_string())
+        log("fuzz(): Mutated data converted as bytes")
+    except Exception:
+        log("fuzz(): Can't convert mutated data to bytes => returning buf")
+        return buf
+
+    # Everything went fine, returning mutated content
+    log("fuzz(): Returning %d bytes" % len(data))
+    return data
+
+
+# Main (for debug)
+if __name__ == "__main__":
+
+    __log__ = True
+    __log_file__ = "/dev/stdout"
+    __seed__ = "RANDOM"
+
+    init(__seed__)
+
+    in_1 = bytearray(
+        "<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>"
+    )
+    in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
+    out = fuzz(in_1, in_2)
+    print(out)
diff --git a/utils/defork/Makefile b/utils/defork/Makefile
new file mode 100644
index 00000000..e8240dba
--- /dev/null
+++ b/utils/defork/Makefile
@@ -0,0 +1,64 @@
+#
+# american fuzzy lop++ - defork
+# ----------------------------------
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS  += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
+#  M32FLAG = -mbe32
+# endif
+#endif
+
+all: defork32.so defork64.so
+
+defork32.so: defork.c
+	-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)"
+
+defork64.so: defork.c
+	-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)"
+
+install: defork32.so defork64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+target:
+	../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror
+
+clean:
+	rm -f defork32.so defork64.so forking_target
diff --git a/utils/defork/README.md b/utils/defork/README.md
new file mode 100644
index 00000000..7e950323
--- /dev/null
+++ b/utils/defork/README.md
@@ -0,0 +1,11 @@
+# defork
+
+when the target forks, this breaks all normal fuzzing runs.
+Sometimes, though, it is enough to just run the child process.
+If this is the case, then this LD_PRELOAD library will always return 0 on fork,
+the target will belive it is running as the child, post-fork.
+
+This is defork.c from the amazing preeny project
+https://github.com/zardus/preeny
+
+It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked.
diff --git a/utils/defork/defork.c b/utils/defork/defork.c
new file mode 100644
index 00000000..c9be3283
--- /dev/null
+++ b/utils/defork/defork.c
@@ -0,0 +1,51 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "../../include/config.h"
+#include "../../include/types.h"
+
+/* we want to fork once (for the afl++ forkserver),
+   then immediately return as child on subsequent forks. */
+static bool forked = 0;
+
+pid_t (*original_fork)(void);
+
+/* In case we are not running in afl, we use a dummy original_fork */
+static pid_t nop(void) {
+
+  return 0;
+
+}
+
+__attribute__((constructor)) void preeny_fork_orig() {
+
+  if (getenv(SHM_ENV_VAR)) {
+
+    printf("defork: running in AFL++. Allowing forkserver.\n");
+    original_fork = dlsym(RTLD_NEXT, "socket");
+
+  } else {
+
+    printf("defork: no AFL++ detected. Disabling fork from the start.\n");
+    original_fork = &nop;
+
+  }
+
+}
+
+pid_t fork(void) {
+
+  /* If we forked before, or if we're in the child (pid==0),
+    we don't want to fork anymore, else, we are still in the forkserver.
+    The forkserver parent needs to fork infinite times, each child should never
+    fork again. This can be written without branches and I hate myself for it.
+  */
+  pid_t ret = !forked && original_fork();
+  forked = !ret;
+  return ret;
+
+}
+
diff --git a/utils/defork/forking_target.c b/utils/defork/forking_target.c
new file mode 100644
index 00000000..628d23c9
--- /dev/null
+++ b/utils/defork/forking_target.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/* This is an example target for defork.c - fuzz using
+```
+mkdir in; echo a > ./in/a
+AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@
+```
+*/
+
+int main(int argc, char **argv) {
+
+  if (argc < 2) {
+
+    printf("Example tool to test defork.\nUsage ./forking_target <input>\n");
+    return -1;
+
+  }
+
+  pid_t pid = fork();
+  if (pid == 0) {
+
+    printf("We're in the child.\n");
+    FILE *f = fopen(argv[1], "r");
+    char  buf[4096];
+    fread(buf, 1, 4096, f);
+    fclose(f);
+    uint32_t offset = buf[100] + (buf[101] << 8);
+    char     test_val = buf[offset];
+    return test_val < 100;
+
+  } else if (pid < 0) {
+
+    perror("fork");
+    return -1;
+
+  } else {
+
+    printf("We are in the parent - defork didn't work! :( (pid=%d)\n",
+           (int)pid);
+
+  }
+
+  return 0;
+
+}
+
diff --git a/utils/distributed_fuzzing/sync_script.sh b/utils/distributed_fuzzing/sync_script.sh
new file mode 100755
index 00000000..b28ff6cd
--- /dev/null
+++ b/utils/distributed_fuzzing/sync_script.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - fuzzer synchronization tool
+# --------------------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2014 Google Inc. All rights reserved.
+# Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+# To make this script work:
+#
+# - Edit FUZZ_HOSTS, FUZZ_DOMAIN, FUZZ_USER, and SYNC_DIR to reflect your
+#   environment.
+#
+# - Make sure that the system you are running this on can log into FUZZ_HOSTS
+#   without a password (authorized_keys or otherwise).
+#
+# - Make sure that every fuzzer is running with -o pointing to SYNC_DIR and -S
+#   that consists of its local host name, followed by an underscore, and then
+#   by some host-local fuzzer ID.
+#
+
+# Hosts to synchronize the data across.
+FUZZ_HOSTS='host1 host2 host3 host4'
+
+# Domain for all hosts
+FUZZ_DOMAIN='example.com'
+
+# Remote user for SSH
+FUZZ_USER=bob
+
+# Directory to synchronize
+SYNC_DIR='/home/bob/sync_dir'
+
+# We only capture -M main nodes, set the name to your chosen naming scheme
+MAIN_NAME='main'
+
+# Interval (seconds) between sync attempts (eg one hour)
+SYNC_INTERVAL=$((60 * 60))
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+  if [ "$PWD" = "/tmp" -o "$PWD" = "/var/tmp" ]; then
+    echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+    exit 1
+  fi
+
+fi
+
+rm -rf .sync_tmp 2>/dev/null
+mkdir .sync_tmp || exit 1
+
+while :; do
+
+  # Pull data in...
+
+  for host in $FUZZ_HOSTS; do
+
+    echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..."
+
+    ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \
+      "cd '$SYNC_DIR' && tar -czf - ${host}_${MAIN_NAME}*/" > ".sync_tmp/${host}.tgz"
+
+  done
+
+  # Distribute data. For large fleets, see tips in the docs/ directory.
+
+  for dst_host in $FUZZ_HOSTS; do
+
+    echo "[*] Distributing data to ${dst_host}.${FUZZ_DOMAIN}..."
+
+    for src_host in $FUZZ_HOSTS; do
+
+      test "$src_host" = "$dst_host" && continue
+
+      echo "    Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..."
+
+      ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \
+        "cd '$SYNC_DIR' && tar -xkzf - " < ".sync_tmp/${src_host}.tgz"
+
+    done
+
+  done
+
+  echo "[+] Done. Sleeping for $SYNC_INTERVAL seconds (Ctrl-C to quit)."
+
+  sleep $SYNC_INTERVAL
+
+done
+
diff --git a/utils/libdislocator/Makefile b/utils/libdislocator/Makefile
new file mode 100644
index 00000000..f0b4bb72
--- /dev/null
+++ b/utils/libdislocator/Makefile
@@ -0,0 +1,43 @@
+#
+# american fuzzy lop++ - libdislocator
+# ----------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+
+PREFIX      ?= /usr/local
+HELPER_PATH  = $(PREFIX)/lib/afl
+
+VERSION     = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
+
+CFLAGS      ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
+override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
+
+CFLAGS_ADD=$(USEHUGEPAGE:1=-DUSEHUGEPAGE)
+CFLAGS += $(CFLAGS_ADD)
+
+all: libdislocator.so
+
+libdislocator.so: libdislocator.so.c ../../config.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC libdislocator.so.c -o $@ $(LDFLAGS)
+	cp -fv libdislocator.so ../../
+
+.NOTPARALLEL: clean
+
+clean:
+	rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
+	rm -f ../../libdislocator.so
+
+install: all
+	install -m 755 -d $${DESTDIR}$(HELPER_PATH)
+	install -m 755 ../../libdislocator.so $${DESTDIR}$(HELPER_PATH)
+	install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md
+
diff --git a/utils/libdislocator/README.md b/utils/libdislocator/README.md
new file mode 100644
index 00000000..d0340af0
--- /dev/null
+++ b/utils/libdislocator/README.md
@@ -0,0 +1,68 @@
+# libdislocator, an abusive allocator
+
+  (See ../../README.md for the general instruction manual.)
+
+This is a companion library that can be used as a drop-in replacement for the
+libc allocator in the fuzzed binaries. It improves the odds of bumping into
+heap-related security bugs in several ways:
+
+  - It allocates all buffers so that they are immediately adjacent to a
+    subsequent PROT_NONE page, causing most off-by-one reads and writes to
+    immediately segfault,
+
+  - It adds a canary immediately below the allocated buffer, to catch writes
+    to negative offsets (won't catch reads, though),
+
+  - It sets the memory returned by malloc() to garbage values, improving the
+    odds of crashing when the target accesses uninitialized data,
+
+  - It sets freed memory to PROT_NONE and does not actually reuse it, causing
+    most use-after-free bugs to segfault right away,
+
+  - It forces all realloc() calls to return a new address - and sets
+    PROT_NONE on the original block. This catches use-after-realloc bugs,
+
+  - It checks for calloc() overflows and can cause soft or hard failures
+    of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB,
+    AFL_LD_HARD_FAIL).
+
+  - Optionally, in platforms supporting it, huge pages can be used by passing
+    USEHUGEPAGE=1 to make.
+  
+  - Size alignment to `max_align_t` can be enforced with AFL_ALIGNED_ALLOC=1.
+    In this case, a tail canary is inserted in the padding bytes at the end
+    of the allocated zone. This reduce the ability of libdislocator to detect
+    off-by-one bugs but also it make slibdislocator compliant to the C standard.
+
+Basically, it is inspired by some of the non-default options available for the
+OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is
+also somewhat similar to several other debugging libraries, such as gmalloc
+and DUMA - but is simple, plug-and-play, and designed specifically for fuzzing
+jobs.
+
+Note that it does nothing for stack-based memory handling errors. The
+-fstack-protector-all setting for GCC / clang, enabled when using AFL_HARDEN,
+can catch some subset of that.
+
+The allocator is slow and memory-intensive (even the tiniest allocation uses up
+4 kB of physical memory and 8 kB of virtual mem), making it completely unsuitable
+for "production" uses; but it can be faster and more hassle-free than ASAN / MSAN
+when fuzzing small, self-contained binaries.
+
+To use this library, run AFL like so:
+
+```
+AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...]
+```
+
+You *have* to specify path, even if it's just ./libdislocator.so or
+$PWD/libdislocator.so.
+
+Similarly to afl-tmin, the library is not "proprietary" and can be used with
+other fuzzers or testing tools without the need for any code tweaks. It does not
+require AFL-instrumented binaries to work.
+
+Note that the AFL_PRELOAD approach (which AFL internally maps to LD_PRELOAD or
+DYLD_INSERT_LIBRARIES, depending on the OS) works only if the target binary is
+dynamically linked. Otherwise, attempting to use the library will have no
+effect.
diff --git a/utils/libdislocator/libdislocator.so.c b/utils/libdislocator/libdislocator.so.c
new file mode 100644
index 00000000..c041fec6
--- /dev/null
+++ b/utils/libdislocator/libdislocator.so.c
@@ -0,0 +1,546 @@
+/*
+
+   american fuzzy lop++ - dislocator, an abusive allocator
+   -----------------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2016 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   This is a companion library that can be used as a drop-in replacement
+   for the libc allocator in the fuzzed binaries. See README.dislocator.md for
+   more info.
+
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#ifdef __APPLE__
+  #include <mach/vm_statistics.h>
+#endif
+
+#ifdef __FreeBSD__
+  #include <sys/param.h>
+#endif
+
+#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__HAIKU__)
+  #include <unistd.h>
+  #ifdef __linux__
+    #include <sys/syscall.h>
+    #include <malloc.h>
+  #endif
+  #ifdef __NR_getrandom
+    #define arc4random_buf(p, l)                       \
+      do {                                             \
+                                                       \
+        ssize_t rd = syscall(__NR_getrandom, p, l, 0); \
+        if (rd != l) DEBUGF("getrandom failed");       \
+                                                       \
+      } while (0)
+
+  #else
+    #include <time.h>
+    #define arc4random_buf(p, l)     \
+      do {                           \
+                                     \
+        srand(time(NULL));           \
+        u32 i;                       \
+        u8 *ptr = (u8 *)p;           \
+        for (i = 0; i < l; i++)      \
+          ptr[i] = rand() % INT_MAX; \
+                                     \
+      } while (0)
+
+  #endif
+#endif
+
+#include "config.h"
+#include "types.h"
+
+#if __STDC_VERSION__ < 201112L || \
+    (defined(__FreeBSD__) && __FreeBSD_version < 1200000)
+// use this hack if not C11
+typedef struct {
+
+  long long   __ll;
+  long double __ld;
+
+} max_align_t;
+
+#endif
+
+#define ALLOC_ALIGN_SIZE (_Alignof(max_align_t))
+
+#ifndef PAGE_SIZE
+  #define PAGE_SIZE 4096
+#endif                                                        /* !PAGE_SIZE */
+
+#ifndef MAP_ANONYMOUS
+  #define MAP_ANONYMOUS MAP_ANON
+#endif                                                    /* !MAP_ANONYMOUS */
+
+#define SUPER_PAGE_SIZE 1 << 21
+
+/* Error / message handling: */
+
+#define DEBUGF(_x...)                 \
+  do {                                \
+                                      \
+    if (alloc_verbose) {              \
+                                      \
+      if (++call_depth == 1) {        \
+                                      \
+        fprintf(stderr, "[AFL] " _x); \
+        fprintf(stderr, "\n");        \
+                                      \
+      }                               \
+      call_depth--;                   \
+                                      \
+    }                                 \
+                                      \
+  } while (0)
+
+#define FATAL(_x...)                    \
+  do {                                  \
+                                        \
+    if (++call_depth == 1) {            \
+                                        \
+      fprintf(stderr, "*** [AFL] " _x); \
+      fprintf(stderr, " ***\n");        \
+      abort();                          \
+                                        \
+    }                                   \
+    call_depth--;                       \
+                                        \
+  } while (0)
+
+/* Macro to count the number of pages needed to store a buffer: */
+
+#define PG_COUNT(_l) (((_l) + (PAGE_SIZE - 1)) / PAGE_SIZE)
+
+/* Canary & clobber bytes: */
+
+#define ALLOC_CANARY 0xAACCAACC
+#define ALLOC_CLOBBER 0xCC
+
+#define TAIL_ALLOC_CANARY 0xAC
+
+#define PTR_C(_p) (((u32 *)(_p))[-1])
+#define PTR_L(_p) (((u32 *)(_p))[-2])
+
+/* Configurable stuff (use AFL_LD_* to set): */
+
+static u32 max_mem = MAX_ALLOC;         /* Max heap usage to permit         */
+static u8  alloc_verbose,               /* Additional debug messages        */
+    hard_fail,                          /* abort() when max_mem exceeded?   */
+    no_calloc_over,                     /* abort() on calloc() overflows?   */
+    align_allocations;                  /* Force alignment to sizeof(void*) */
+
+#if defined __OpenBSD__ || defined __APPLE__
+  #define __thread
+  #warning no thread support available
+#endif
+static __thread size_t total_mem;       /* Currently allocated mem          */
+
+static __thread u32 call_depth;         /* To avoid recursion via fprintf() */
+static u32          alloc_canary;
+
+/* This is the main alloc function. It allocates one page more than necessary,
+   sets that tailing page to PROT_NONE, and then increments the return address
+   so that it is right-aligned to that boundary. Since it always uses mmap(),
+   the returned memory will be zeroed. */
+
+static void *__dislocator_alloc(size_t len) {
+
+  u8 *   ret, *base;
+  size_t tlen;
+  int    flags, fd, sp;
+
+  if (total_mem + len > max_mem || total_mem + len < total_mem) {
+
+    if (hard_fail) FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024);
+
+    DEBUGF("total allocs exceed %u MB, returning NULL", max_mem / 1024 / 1024);
+
+    return NULL;
+
+  }
+
+  size_t rlen;
+  if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1)))
+    rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
+  else
+    rlen = len;
+
+  /* We will also store buffer length and a canary below the actual buffer, so
+     let's add 8 bytes for that. */
+
+  base = NULL;
+  tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
+  flags = MAP_PRIVATE | MAP_ANONYMOUS;
+  fd = -1;
+#if defined(USEHUGEPAGE)
+  sp = (rlen >= SUPER_PAGE_SIZE && !(rlen % SUPER_PAGE_SIZE));
+
+  #if defined(__APPLE__)
+  if (sp) fd = VM_FLAGS_SUPERPAGE_SIZE_2MB;
+  #elif defined(__linux__)
+  if (sp) flags |= MAP_HUGETLB;
+  #elif defined(__FreeBSD__)
+  if (sp) flags |= MAP_ALIGNED_SUPER;
+  #elif defined(__sun)
+  if (sp) {
+
+    base = (void *)(caddr_t)(1 << 21);
+    flags |= MAP_ALIGN;
+
+  }
+
+  #endif
+#else
+  (void)sp;
+#endif
+
+  ret = (u8 *)mmap(base, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
+#if defined(USEHUGEPAGE)
+  /* We try one more time with regular call */
+  if (ret == MAP_FAILED) {
+
+  #if defined(__APPLE__)
+    fd = -1;
+  #elif defined(__linux__)
+    flags &= -MAP_HUGETLB;
+  #elif defined(__FreeBSD__)
+    flags &= -MAP_ALIGNED_SUPER;
+  #elif defined(__sun)
+    flags &= -MAP_ALIGN;
+  #endif
+    ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
+
+  }
+
+#endif
+
+  if (ret == MAP_FAILED) {
+
+    if (hard_fail) FATAL("mmap() failed on alloc (OOM?)");
+
+    DEBUGF("mmap() failed on alloc (OOM?)");
+
+    return NULL;
+
+  }
+
+  /* Set PROT_NONE on the last page. */
+
+  if (mprotect(ret + PG_COUNT(rlen + 8) * PAGE_SIZE, PAGE_SIZE, PROT_NONE))
+    FATAL("mprotect() failed when allocating memory");
+
+  /* Offset the return pointer so that it's right-aligned to the page
+     boundary. */
+
+  ret += PAGE_SIZE * PG_COUNT(rlen + 8) - rlen - 8;
+
+  /* Store allocation metadata. */
+
+  ret += 8;
+
+  PTR_L(ret) = len;
+  PTR_C(ret) = alloc_canary;
+
+  total_mem += len;
+
+  if (rlen != len) {
+
+    size_t i;
+    for (i = len; i < rlen; ++i)
+      ret[i] = TAIL_ALLOC_CANARY;
+
+  }
+
+  return ret;
+
+}
+
+/* The "user-facing" wrapper for calloc(). This just checks for overflows and
+   displays debug messages if requested. */
+
+void *calloc(size_t elem_len, size_t elem_cnt) {
+
+  void *ret;
+
+  size_t len = elem_len * elem_cnt;
+
+  /* Perform some sanity checks to detect obvious issues... */
+
+  if (elem_cnt && len / elem_cnt != elem_len) {
+
+    if (no_calloc_over) {
+
+      DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len,
+             elem_cnt);
+      return NULL;
+
+    }
+
+    FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt);
+
+  }
+
+  ret = __dislocator_alloc(len);
+
+  DEBUGF("calloc(%zu, %zu) = %p [%zu total]", elem_len, elem_cnt, ret,
+         total_mem);
+
+  return ret;
+
+}
+
+/* The wrapper for malloc(). Roughly the same, also clobbers the returned
+   memory (unlike calloc(), malloc() is not guaranteed to return zeroed
+   memory). */
+
+void *malloc(size_t len) {
+
+  void *ret;
+
+  ret = __dislocator_alloc(len);
+
+  DEBUGF("malloc(%zu) = %p [%zu total]", len, ret, total_mem);
+
+  if (ret && len) memset(ret, ALLOC_CLOBBER, len);
+
+  return ret;
+
+}
+
+/* The wrapper for free(). This simply marks the entire region as PROT_NONE.
+   If the region is already freed, the code will segfault during the attempt to
+   read the canary. Not very graceful, but works, right? */
+
+void free(void *ptr) {
+
+  u32 len;
+
+  DEBUGF("free(%p)", ptr);
+
+  if (!ptr) return;
+
+  if (PTR_C(ptr) != alloc_canary) FATAL("bad allocator canary on free()");
+
+  len = PTR_L(ptr);
+
+  total_mem -= len;
+  u8 *ptr_ = ptr;
+
+  if (align_allocations && (len & (ALLOC_ALIGN_SIZE - 1))) {
+
+    size_t rlen = (len & ~(ALLOC_ALIGN_SIZE - 1)) + ALLOC_ALIGN_SIZE;
+    for (; len < rlen; ++len)
+      if (ptr_[len] != TAIL_ALLOC_CANARY)
+        FATAL("bad tail allocator canary on free()");
+
+  }
+
+  /* Protect everything. Note that the extra page at the end is already
+     set as PROT_NONE, so we don't need to touch that. */
+
+  ptr_ -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8;
+
+  if (mprotect(ptr_ - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE))
+    FATAL("mprotect() failed when freeing memory");
+
+  ptr = ptr_;
+
+  /* Keep the mapping; this is wasteful, but prevents ptr reuse. */
+
+}
+
+/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer,
+   move data, and then free (aka mprotect()) the original one. */
+
+void *realloc(void *ptr, size_t len) {
+
+  void *ret;
+
+  ret = malloc(len);
+
+  if (ret && ptr) {
+
+    if (PTR_C(ptr) != alloc_canary) FATAL("bad allocator canary on realloc()");
+    // Here the tail canary check is delayed to free()
+
+    memcpy(ret, ptr, MIN(len, PTR_L(ptr)));
+    free(ptr);
+
+  }
+
+  DEBUGF("realloc(%p, %zu) = %p [%zu total]", ptr, len, ret, total_mem);
+
+  return ret;
+
+}
+
+/* posix_memalign we mainly check the proper alignment argument
+   if the requested size fits within the alignment we do
+   a normal request */
+
+int posix_memalign(void **ptr, size_t align, size_t len) {
+
+  // if (*ptr == NULL) return EINVAL; // (andrea) Why? I comment it out for now
+  if ((align % 2) || (align % sizeof(void *))) return EINVAL;
+  if (len == 0) {
+
+    *ptr = NULL;
+    return 0;
+
+  }
+
+  size_t rem = len % align;
+  if (rem) len += align - rem;
+
+  *ptr = __dislocator_alloc(len);
+
+  if (*ptr && len) memset(*ptr, ALLOC_CLOBBER, len);
+
+  DEBUGF("posix_memalign(%p %zu, %zu) [*ptr = %p]", ptr, align, len, *ptr);
+
+  return 0;
+
+}
+
+/* just the non-posix fashion */
+
+void *memalign(size_t align, size_t len) {
+
+  void *ret = NULL;
+
+  if (posix_memalign(&ret, align, len)) {
+
+    DEBUGF("memalign(%zu, %zu) failed", align, len);
+
+  }
+
+  return ret;
+
+}
+
+/* sort of C11 alias of memalign only more severe, alignment-wise */
+
+void *aligned_alloc(size_t align, size_t len) {
+
+  void *ret = NULL;
+
+  if ((len % align)) return NULL;
+
+  if (posix_memalign(&ret, align, len)) {
+
+    DEBUGF("aligned_alloc(%zu, %zu) failed", align, len);
+
+  }
+
+  return ret;
+
+}
+
+/* specific BSD api mainly checking possible overflow for the size */
+
+void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) {
+
+  const size_t elem_lim = 1UL << (sizeof(size_t) * 4);
+  const size_t elem_tot = elem_len * elem_cnt;
+  void *       ret = NULL;
+
+  if ((elem_len >= elem_lim || elem_cnt >= elem_lim) && elem_len > 0 &&
+      elem_cnt > (SIZE_MAX / elem_len)) {
+
+    DEBUGF("reallocarray size overflow (%zu)", elem_tot);
+
+  } else {
+
+    ret = realloc(ptr, elem_tot);
+
+  }
+
+  return ret;
+
+}
+
+#if !defined(__ANDROID__)
+size_t malloc_usable_size(void *ptr) {
+
+#else
+size_t malloc_usable_size(const void *ptr) {
+
+#endif
+
+  return ptr ? PTR_L(ptr) : 0;
+
+}
+
+__attribute__((constructor)) void __dislocator_init(void) {
+
+  u8 *tmp = (u8 *)getenv("AFL_LD_LIMIT_MB");
+
+  if (tmp) {
+
+    u8 *tok;
+    s32 mmem = (s32)strtol((char *)tmp, (char **)&tok, 10);
+    if (*tok != '\0' || errno == ERANGE) FATAL("Bad value for AFL_LD_LIMIT_MB");
+    max_mem = mmem * 1024 * 1024;
+
+  }
+
+  alloc_canary = ALLOC_CANARY;
+  tmp = (u8 *)getenv("AFL_RANDOM_ALLOC_CANARY");
+
+  if (tmp) arc4random_buf(&alloc_canary, sizeof(alloc_canary));
+
+  alloc_verbose = !!getenv("AFL_LD_VERBOSE");
+  hard_fail = !!getenv("AFL_LD_HARD_FAIL");
+  no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER");
+  align_allocations = !!getenv("AFL_ALIGNED_ALLOC");
+
+}
+
+/* NetBSD fault handler specific api subset */
+
+void (*esetfunc(void (*fn)(int, const char *, ...)))(int, const char *, ...) {
+
+  /* Might not be meaningful to implement; upper calls already report errors */
+  return NULL;
+
+}
+
+void *emalloc(size_t len) {
+
+  return malloc(len);
+
+}
+
+void *ecalloc(size_t elem_len, size_t elem_cnt) {
+
+  return calloc(elem_len, elem_cnt);
+
+}
+
+void *erealloc(void *ptr, size_t len) {
+
+  return realloc(ptr, len);
+
+}
+
diff --git a/utils/libpng_no_checksum/libpng-nocrc.patch b/utils/libpng_no_checksum/libpng-nocrc.patch
new file mode 100644
index 00000000..0a3793a0
--- /dev/null
+++ b/utils/libpng_no_checksum/libpng-nocrc.patch
@@ -0,0 +1,15 @@
+--- pngrutil.c.orig	2014-06-12 03:35:16.000000000 +0200
++++ pngrutil.c	2014-07-01 05:08:31.000000000 +0200
+@@ -268,7 +268,11 @@
+    if (need_crc != 0)
+    {
+       crc = png_get_uint_32(crc_bytes);
+-      return ((int)(crc != png_ptr->crc));
++
++      if (crc != png_ptr->crc)
++        fprintf(stderr, "NOTE: CRC in the file is 0x%08x, change to 0x%08x\n", crc, png_ptr->crc);
++
++      return ((int)(1 != 1));
+    }
+ 
+    else
diff --git a/utils/libtokencap/Makefile b/utils/libtokencap/Makefile
new file mode 100644
index 00000000..b81e1729
--- /dev/null
+++ b/utils/libtokencap/Makefile
@@ -0,0 +1,94 @@
+#
+# american fuzzy lop++ - libtokencap
+# --------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+
+PREFIX      ?= /usr/local
+HELPER_PATH  = $(PREFIX)/lib/afl
+DOC_PATH    ?= $(PREFIX)/share/doc/afl
+MAN_PATH    ?= $(PREFIX)/share/man/man8
+
+VERSION     = $(shell grep '^\#define VERSION ' ../../config.h | cut -d '"' -f2)
+
+CFLAGS      ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
+override CFLAGS += -I ../../include/ -Wall -g -Wno-pointer-sign
+
+
+UNAME_S =$(shell uname -s)# GNU make
+UNAME_S:sh=uname -s       # BSD make
+_UNIQ=_QINU_
+
+    _OS_DL = $(_UNIQ)$(UNAME_S)
+   __OS_DL =     $(_OS_DL:$(_UNIQ)Linux=$(_UNIQ))
+  ___OS_DL =    $(__OS_DL:$(_UNIQ)Darwin=$(_UNIQ))
+ ____OS_DL =   $(___OS_DL:$(_UNIQ)$(UNAME_S)=)
+_____OS_DL =  $(____OS_DL:$(_UNIQ)="-ldl")
+
+     _OS_TARGET = $(___OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
+    __OS_TARGET =     $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
+   ___OS_TARGET =    $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
+  ____OS_TARGET =   $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
+ _____OS_TARGET =  $(____OS_TARGET:$(_UNIQ)SunOS=$(_UNIQ))
+______OS_TARGET = $(_____OS_TARGET:$(_UNIQ)$(UNAME_S)=)
+
+TARGETS       =  $(______OS_TARGET:$(_UNIQ)=libtokencap.so)
+
+LDFLAGS     += $(_____OS_DL)
+
+#ifeq "$(shell uname)" "Linux"
+#  TARGETS = libtokencap.so
+#  LDFLAGS     += -ldl
+#endif
+#ifeq "$(shell uname)" "Darwin"
+#  TARGETS = libtokencap.so
+#  LDFLAGS     += -ldl
+#endif
+#ifeq "$(shell uname)" "FreeBSD"
+#  TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "OpenBSD"
+#  TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "NetBSD"
+#  TARGETS = libtokencap.so
+#endif
+#ifeq "$(shell uname)" "DragonFly"
+#  TARGETS = libtokencap.so
+#  LDFLAGS     += -ldl
+#endif
+all: $(TARGETS)
+
+libtokencap.so: libtokencap.so.c ../../config.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) -shared -fPIC $< -o $@ $(LDFLAGS)
+	cp -f libtokencap.so ../../
+
+.NOTPARALLEL: clean
+
+debug:
+	@echo $(UNAME_S)$(_UNIQ) | hexdump -C
+	@echo from $(____OS_DL) : $(_UNIQ)$(UNAME_S) = -\> $(_____OS_DL)
+	@echo from $(_____OS_DL) : $(_UNIQ) = -ldl -\> $(______OS_DL)
+	@echo from $(____OS_DL) : $(_UNIQ)FreeBSD = $(_UNIQ) -\> $(_OS_TARGET)
+	@echo from $(_OS_TARGET) : $(_UNIQ)OpenBSD = $(_UNIQ) -\> $(__OS_TARGET)
+	@echo from $(__OS_TARGET) : $(_UNIQ)NetBSD = $(_UNIQ) -\> $(___OS_TARGET)
+	@echo from $(___OS_TARGET) : $(_UNIQ)$(_UNIQ) = -\> $(____OS_TARGET)
+	@echo from $(____OS_TARGET) : $(_UNIQ) = libtokencap.so -\> $(TARGETS)
+
+clean:
+	rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
+	rm -fv ../../libtokencap.so
+
+install: all
+	install -m 755 -d $${DESTDIR}$(HELPER_PATH)
+	install -m 755 ../../libtokencap.so $${DESTDIR}$(HELPER_PATH)
+	install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
diff --git a/utils/libtokencap/README.md b/utils/libtokencap/README.md
new file mode 100644
index 00000000..a39ed3a5
--- /dev/null
+++ b/utils/libtokencap/README.md
@@ -0,0 +1,69 @@
+# strcmp() / memcmp() token capture library
+
+ NOTE: libtokencap is only recommended for binary-only targets or targets that
+ do not compile with afl-clang-fast/afl-clang-lto.
+ The afl-clang-fast AFL_LLVM_DICT2FILE feature is much better, afl-clang-lto
+ has that feature automatically integrated.
+
+  (See ../../README.md for the general instruction manual.)
+
+This companion library allows you to instrument `strcmp()`, `memcmp()`,
+and related functions to automatically extract syntax tokens passed to any of
+these libcalls. The resulting list of tokens may be then given as a starting
+dictionary to afl-fuzz (the -x option) to improve coverage on subsequent
+fuzzing runs.
+
+This may help improving coverage in some targets, and do precisely nothing in
+others. In some cases, it may even make things worse: if libtokencap picks up
+syntax tokens that are not used to process the input data, but that are a part
+of - say - parsing a config file... well, you're going to end up wasting a lot
+of CPU time on trying them out in the input stream. In other words, use this
+feature with care. Manually screening the resulting dictionary is almost
+always a necessity.
+
+As for the actual operation: the library stores tokens, without any deduping,
+by appending them to a file specified via AFL_TOKEN_FILE. If the variable is not
+set, the tool uses stderr (which is probably not what you want).
+
+Similarly to afl-tmin, the library is not "proprietary" and can be used with
+other fuzzers or testing tools without the need for any code tweaks. It does not
+require AFL-instrumented binaries to work.
+
+To use the library, you *need* to make sure that your fuzzing target is compiled
+with -fno-builtin and is linked dynamically. If you wish to automate the first
+part without mucking with CFLAGS in Makefiles, you can set AFL_NO_BUILTIN=1
+when using afl-gcc. This setting specifically adds the following flags:
+
+```
+  -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp
+  -fno-builtin-strcasencmp -fno-builtin-memcmp -fno-builtin-strstr
+  -fno-builtin-strcasestr
+```
+
+The next step is simply loading this library via LD_PRELOAD. The optimal usage
+pattern is to allow afl-fuzz to fuzz normally for a while and build up a corpus,
+and then fire off the target binary, with libtokencap.so loaded, on every file
+found by AFL in that earlier run. This demonstrates the basic principle:
+
+```
+  export AFL_TOKEN_FILE=$PWD/temp_output.txt
+
+  for i in <out_dir>/queue/id*; do
+    LD_PRELOAD=/path/to/libtokencap.so \
+      /path/to/target/program [...params, including $i...]
+  done
+
+  sort -u temp_output.txt >afl_dictionary.txt
+```
+
+If you don't get any results, the target library is probably not using strcmp()
+and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or
+the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect.
+
+Portability hints: There is probably no particularly portable and non-invasive
+way to distinguish between read-only and read-write memory mappings.
+The `__tokencap_load_mappings()` function is the only thing that would
+need to be changed for other OSes.
+
+Current supported OSes are: Linux, Darwin, FreeBSD (thanks to @devnexen)
+
diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c
new file mode 100644
index 00000000..3629e804
--- /dev/null
+++ b/utils/libtokencap/libtokencap.so.c
@@ -0,0 +1,794 @@
+/*
+
+   american fuzzy lop++ - extract tokens passed to strcmp / memcmp
+   -------------------------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2016 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   This Linux-only companion library allows you to instrument strcmp(),
+   memcmp(), and related functions to automatically extract tokens.
+   See README.tokencap.md for more info.
+
+ */
+
+#ifndef _GNU_SOURCE
+  #define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+#include "../types.h"
+#include "../config.h"
+
+#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ &&      \
+    !defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__ && \
+    !defined(__HAIKU__) && !defined(__sun)
+  #error "Sorry, this library is unsupported in this platform for now!"
+#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
+          !__NetBSD__*/
+
+#if defined __APPLE__
+  #include <mach/vm_map.h>
+  #include <mach/mach_init.h>
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+  #include <sys/types.h>
+  #include <sys/sysctl.h>
+  #if !defined __NetBSD__
+    #include <sys/user.h>
+  #endif
+  #include <sys/mman.h>
+#elif defined __HAIKU__
+  #include <kernel/image.h>
+#elif defined __sun
+  /* For map addresses the old struct is enough */
+  #include <sys/procfs.h>
+  #include <limits.h>
+#endif
+
+#include <dlfcn.h>
+
+#ifdef RTLD_NEXT
+/* The libc functions are a magnitude faster than our replacements.
+   Use them when RTLD_NEXT is available. */
+int (*__libc_strcmp)(const char *str1, const char *str2);
+int (*__libc_strncmp)(const char *str1, const char *str2, size_t len);
+int (*__libc_strcasecmp)(const char *str1, const char *str2);
+int (*__libc_strncasecmp)(const char *str1, const char *str2, size_t len);
+int (*__libc_memcmp)(const void *mem1, const void *mem2, size_t len);
+int (*__libc_bcmp)(const void *mem1, const void *mem2, size_t len);
+char *(*__libc_strstr)(const char *haystack, const char *needle);
+char *(*__libc_strcasestr)(const char *haystack, const char *needle);
+void *(*__libc_memmem)(const void *haystack, size_t haystack_len,
+                       const void *needle, size_t needle_len);
+#endif
+
+/* Mapping data and such */
+
+#define MAX_MAPPINGS 1024
+
+static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS];
+
+static u32   __tokencap_ro_cnt;
+static u8    __tokencap_ro_loaded;
+static int   __tokencap_out_file = -1;
+static pid_t __tokencap_pid = -1;
+
+/* Identify read-only regions in memory. Only parameters that fall into these
+   ranges are worth dumping when passed to strcmp() and so on. Read-write
+   regions are far more likely to contain user input instead. */
+
+static void __tokencap_load_mappings(void) {
+
+#if defined __linux__
+
+  u8    buf[MAX_LINE];
+  FILE *f = fopen("/proc/self/maps", "r");
+
+  __tokencap_ro_loaded = 1;
+
+  if (!f) return;
+
+  while (fgets(buf, MAX_LINE, f)) {
+
+    u8    rf, wf;
+    void *st, *en;
+
+    if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue;
+    if (wf == 'w' || rf != 'r') continue;
+
+    __tokencap_ro[__tokencap_ro_cnt].st = (void *)st;
+    __tokencap_ro[__tokencap_ro_cnt].en = (void *)en;
+
+    if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+  }
+
+  fclose(f);
+
+#elif defined __APPLE__
+
+  struct vm_region_submap_info_64 region;
+  mach_msg_type_number_t          cnt = VM_REGION_SUBMAP_INFO_COUNT_64;
+  vm_address_t                    base = 0;
+  vm_size_t                       size = 0;
+  natural_t                       depth = 0;
+
+  __tokencap_ro_loaded = 1;
+
+  while (1) {
+
+    if (vm_region_recurse_64(mach_task_self(), &base, &size, &depth,
+                             (vm_region_info_64_t)&region,
+                             &cnt) != KERN_SUCCESS)
+      break;
+
+    if (region.is_submap) {
+
+      depth++;
+
+    } else {
+
+      /* We only care of main map addresses and the read only kinds */
+      if ((region.protection & VM_PROT_READ) &&
+          !(region.protection & VM_PROT_WRITE)) {
+
+        __tokencap_ro[__tokencap_ro_cnt].st = (void *)base;
+        __tokencap_ro[__tokencap_ro_cnt].en = (void *)(base + size);
+
+        if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+      }
+
+      base += size;
+      size = 0;
+
+    }
+
+  }
+
+#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__
+
+  #if defined   __FreeBSD__
+  int    mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid};
+  #elif defined __OpenBSD__
+  int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid};
+  #elif defined __NetBSD__
+  int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid,
+               sizeof(struct kinfo_vmentry)};
+  #endif
+  char * buf, *low, *high;
+  size_t miblen = sizeof(mib) / sizeof(mib[0]);
+  size_t len;
+
+  if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return;
+
+  #if defined __FreeBSD__ || defined __NetBSD__
+  len = len * 4 / 3;
+  #elif defined                      __OpenBSD__
+  len -= len % sizeof(struct kinfo_vmentry);
+  #endif
+
+  buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+  if (buf == MAP_FAILED) return;
+
+  if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
+
+    munmap(buf, len);
+    return;
+
+  }
+
+  low = buf;
+  high = low + len;
+
+  __tokencap_ro_loaded = 1;
+
+  while (low < high) {
+
+    struct kinfo_vmentry *region = (struct kinfo_vmentry *)low;
+
+  #if defined __FreeBSD__ || defined __NetBSD__
+
+    #if defined   __FreeBSD__
+    size_t                size = region->kve_structsize;
+
+    if (size == 0) break;
+    #elif defined __NetBSD__
+    size_t size = sizeof(*region);
+    #endif
+
+    /* We go through the whole mapping of the process and track read-only
+     * addresses */
+    if ((region->kve_protection & KVME_PROT_READ) &&
+        !(region->kve_protection & KVME_PROT_WRITE)) {
+
+  #elif defined __OpenBSD__
+
+    size_t size = sizeof(*region);
+
+    /* We go through the whole mapping of the process and track read-only
+     * addresses */
+    if ((region->kve_protection & KVE_PROT_READ) &&
+        !(region->kve_protection & KVE_PROT_WRITE)) {
+
+  #endif
+      __tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start;
+      __tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end;
+
+      if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+    }
+
+    low += size;
+
+  }
+
+  munmap(buf, len);
+#elif defined __HAIKU__
+  image_info ii;
+  int32_t    group = 0;
+
+  __tokencap_ro_loaded = 1;
+
+  while (get_next_image_info(0, &group, &ii) == B_OK) {
+
+    __tokencap_ro[__tokencap_ro_cnt].st = ii.text;
+    __tokencap_ro[__tokencap_ro_cnt].en = ((char *)ii.text) + ii.text_size;
+
+    if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+  }
+
+#elif defined __sun
+  prmap_t *c, *map;
+  char     path[PATH_MAX];
+  ssize_t  r;
+  size_t   hint;
+  int      fd;
+
+  snprintf(path, sizeof(path), "/proc/%ld/map", getpid());
+  fd = open(path, O_RDONLY);
+  hint = (1 << 20);
+  map = malloc(hint);
+
+  __tokencap_ro_loaded = 1;
+
+  for (; (r = pread(fd, map, hint, 0)) == hint;) {
+
+    hint <<= 1;
+    map = realloc(map, hint);
+
+  }
+
+  for (c = map; r > 0; c++, r -= sizeof(prmap_t)) {
+
+    __tokencap_ro[__tokencap_ro_cnt].st = (void *)c->pr_vaddr;
+    __tokencap_ro[__tokencap_ro_cnt].en = (void *)(c->pr_vaddr + c->pr_size);
+
+    if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+  }
+
+  free(map);
+  close(fd);
+#endif
+
+}
+
+/* Check an address against the list of read-only mappings. */
+
+static u8 __tokencap_is_ro(const void *ptr) {
+
+  u32 i;
+
+  if (!__tokencap_ro_loaded) __tokencap_load_mappings();
+
+  for (i = 0; i < __tokencap_ro_cnt; i++)
+    if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1;
+
+  return 0;
+
+}
+
+/* Dump an interesting token to output file, quoting and escaping it
+   properly. */
+
+static void __tokencap_dump(const u8 *ptr, size_t len, u8 is_text) {
+
+  u8  buf[MAX_AUTO_EXTRA * 4 + 1];
+  u32 i;
+  u32 pos = 0;
+
+  if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || __tokencap_out_file == -1)
+    return;
+
+  for (i = 0; i < len; i++) {
+
+    if (is_text && !ptr[i]) break;
+
+    switch (ptr[i]) {
+
+      case 0 ... 31:
+      case 127 ... 255:
+      case '\"':
+      case '\\':
+
+        sprintf(buf + pos, "\\x%02x", ptr[i]);
+        pos += 4;
+        break;
+
+      default:
+        buf[pos++] = ptr[i];
+
+    }
+
+  }
+
+  buf[pos] = 0;
+
+  int wrt_ok = (1 == write(__tokencap_out_file, "\"", 1));
+  wrt_ok &= (pos == write(__tokencap_out_file, buf, pos));
+  wrt_ok &= (2 == write(__tokencap_out_file, "\"\n", 2));
+
+}
+
+/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used
+   only if the target is compiled with -fno-builtins and linked dynamically. */
+
+#undef strcmp
+
+int strcmp(const char *str1, const char *str2) {
+
+  if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
+  if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strcmp) return __libc_strcmp(str1, str2);
+#endif
+
+  while (1) {
+
+    const unsigned char c1 = *str1, c2 = *str2;
+
+    if (c1 != c2) return (c1 > c2) ? 1 : -1;
+    if (!c1) return 0;
+    str1++;
+    str2++;
+
+  }
+
+}
+
+#undef strncmp
+
+int strncmp(const char *str1, const char *str2, size_t len) {
+
+  if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
+  if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strncmp) return __libc_strncmp(str1, str2, len);
+#endif
+
+  while (len--) {
+
+    unsigned char c1 = *str1, c2 = *str2;
+
+    if (c1 != c2) return (c1 > c2) ? 1 : -1;
+    if (!c1) return 0;
+    str1++;
+    str2++;
+
+  }
+
+  return 0;
+
+}
+
+#undef strcasecmp
+
+int strcasecmp(const char *str1, const char *str2) {
+
+  if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1);
+  if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strcasecmp) return __libc_strcasecmp(str1, str2);
+#endif
+
+  while (1) {
+
+    const unsigned char c1 = tolower((int)*str1), c2 = tolower((int)*str2);
+
+    if (c1 != c2) return (c1 > c2) ? 1 : -1;
+    if (!c1) return 0;
+    str1++;
+    str2++;
+
+  }
+
+}
+
+#undef strncasecmp
+
+int strncasecmp(const char *str1, const char *str2, size_t len) {
+
+  if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1);
+  if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strncasecmp) return __libc_strncasecmp(str1, str2, len);
+#endif
+
+  while (len--) {
+
+    const unsigned char c1 = tolower((int)*str1), c2 = tolower((int)*str2);
+
+    if (c1 != c2) return (c1 > c2) ? 1 : -1;
+    if (!c1) return 0;
+    str1++;
+    str2++;
+
+  }
+
+  return 0;
+
+}
+
+#undef memcmp
+
+int memcmp(const void *mem1, const void *mem2, size_t len) {
+
+  if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
+  if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
+
+#ifdef RTLD_NEXT
+  if (__libc_memcmp) return __libc_memcmp(mem1, mem2, len);
+#endif
+
+  const char *strmem1 = (const char *)mem1;
+  const char *strmem2 = (const char *)mem2;
+
+  while (len--) {
+
+    const unsigned char c1 = *strmem1, c2 = *strmem2;
+    if (c1 != c2) return (c1 > c2) ? 1 : -1;
+    strmem1++;
+    strmem2++;
+
+  }
+
+  return 0;
+
+}
+
+#undef bcmp
+
+int bcmp(const void *mem1, const void *mem2, size_t len) {
+
+  if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0);
+  if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0);
+
+#ifdef RTLD_NEXT
+  if (__libc_bcmp) return __libc_bcmp(mem1, mem2, len);
+#endif
+
+  const char *strmem1 = (const char *)mem1;
+  const char *strmem2 = (const char *)mem2;
+
+  while (len--) {
+
+    int diff = *strmem1 ^ *strmem2;
+    if (diff != 0) return 1;
+    strmem1++;
+    strmem2++;
+
+  }
+
+  return 0;
+
+}
+
+#undef strstr
+
+char *strstr(const char *haystack, const char *needle) {
+
+  if (__tokencap_is_ro(haystack))
+    __tokencap_dump(haystack, strlen(haystack), 1);
+
+  if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strstr) return __libc_strstr(haystack, needle);
+#endif
+
+  do {
+
+    const char *n = needle;
+    const char *h = haystack;
+
+    while (*n && *h && *n == *h)
+      n++, h++;
+
+    if (!*n) return (char *)haystack;
+
+  } while (*(haystack++));
+
+  return 0;
+
+}
+
+#undef strcasestr
+
+char *strcasestr(const char *haystack, const char *needle) {
+
+  if (__tokencap_is_ro(haystack))
+    __tokencap_dump(haystack, strlen(haystack), 1);
+
+  if (__tokencap_is_ro(needle)) __tokencap_dump(needle, strlen(needle), 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_strcasestr) return __libc_strcasestr(haystack, needle);
+#endif
+
+  do {
+
+    const char *n = needle;
+    const char *h = haystack;
+
+    while (*n && *h && tolower((int)*n) == tolower((int)*h))
+      n++, h++;
+
+    if (!*n) return (char *)haystack;
+
+  } while (*(haystack++));
+
+  return 0;
+
+}
+
+#undef memmem
+
+void *memmem(const void *haystack, size_t haystack_len, const void *needle,
+             size_t needle_len) {
+
+  if (__tokencap_is_ro(haystack)) __tokencap_dump(haystack, haystack_len, 1);
+
+  if (__tokencap_is_ro(needle)) __tokencap_dump(needle, needle_len, 1);
+
+#ifdef RTLD_NEXT
+  if (__libc_memmem)
+    return __libc_memmem(haystack, haystack_len, needle, needle_len);
+#endif
+
+  const char *n = (const char *)needle;
+  const char *h = (const char *)haystack;
+  if (haystack_len < needle_len) return 0;
+  if (needle_len == 0) return (void *)haystack;
+  if (needle_len == 1) return memchr(haystack, *n, haystack_len);
+
+  const char *end = h + (haystack_len - needle_len);
+
+  do {
+
+    if (*h == *n) {
+
+      if (memcmp(h, n, needle_len) == 0) return (void *)h;
+
+    }
+
+  } while (h++ <= end);
+
+  return 0;
+
+}
+
+/* Common libraries wrappers (from honggfuzz) */
+
+/*
+ * Apache's httpd wrappers
+ */
+int ap_cstr_casecmp(const char *s1, const char *s2) {
+
+  return strcasecmp(s1, s2);
+
+}
+
+int ap_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
+
+  return strncasecmp(s1, s2, n);
+
+}
+
+const char *ap_strcasestr(const char *s1, const char *s2) {
+
+  return strcasestr(s1, s2);
+
+}
+
+int apr_cstr_casecmp(const char *s1, const char *s2) {
+
+  return strcasecmp(s1, s2);
+
+}
+
+int apr_cstr_casecmpn(const char *s1, const char *s2, size_t n) {
+
+  return strncasecmp(s1, s2, n);
+
+}
+
+/*
+ * *SSL wrappers
+ */
+int CRYPTO_memcmp(const void *m1, const void *m2, size_t len) {
+
+  return memcmp(m1, m2, len);
+
+}
+
+int OPENSSL_memcmp(const void *m1, const void *m2, size_t len) {
+
+  return memcmp(m1, m2, len);
+
+}
+
+int OPENSSL_strcasecmp(const char *s1, const char *s2) {
+
+  return strcasecmp(s1, s2);
+
+}
+
+int OPENSSL_strncasecmp(const char *s1, const char *s2, size_t len) {
+
+  return strncasecmp(s1, s2, len);
+
+}
+
+int32_t memcmpct(const void *s1, const void *s2, size_t len) {
+
+  return memcmp(s1, s2, len);
+
+}
+
+/*
+ * libXML wrappers
+ */
+int xmlStrncmp(const char *s1, const char *s2, int len) {
+
+  if (len <= 0) { return 0; }
+  if (s1 == s2) { return 0; }
+  if (s1 == NULL) { return -1; }
+  if (s2 == NULL) { return 1; }
+  return strncmp(s1, s2, (size_t)len);
+
+}
+
+int xmlStrcmp(const char *s1, const char *s2) {
+
+  if (s1 == s2) { return 0; }
+  if (s1 == NULL) { return -1; }
+  if (s2 == NULL) { return 1; }
+  return strcmp(s1, s2);
+
+}
+
+int xmlStrEqual(const char *s1, const char *s2) {
+
+  if (s1 == s2) { return 1; }
+  if (s1 == NULL) { return 0; }
+  if (s2 == NULL) { return 0; }
+  if (strcmp(s1, s2) == 0) { return 1; }
+  return 0;
+
+}
+
+int xmlStrcasecmp(const char *s1, const char *s2) {
+
+  if (s1 == s2) { return 0; }
+  if (s1 == NULL) { return -1; }
+  if (s2 == NULL) { return 1; }
+  return strcasecmp(s1, s2);
+
+}
+
+int xmlStrncasecmp(const char *s1, const char *s2, int len) {
+
+  if (len <= 0) { return 0; }
+  if (s1 == s2) { return 0; }
+  if (s1 == NULL) { return -1; }
+  if (s2 == NULL) { return 1; }
+  return strncasecmp(s1, s2, (size_t)len);
+
+}
+
+const char *xmlStrstr(const char *haystack, const char *needle) {
+
+  if (haystack == NULL) { return NULL; }
+  if (needle == NULL) { return NULL; }
+  return strstr(haystack, needle);
+
+}
+
+const char *xmlStrcasestr(const char *haystack, const char *needle) {
+
+  if (haystack == NULL) { return NULL; }
+  if (needle == NULL) { return NULL; }
+  return strcasestr(haystack, needle);
+
+}
+
+/*
+ * Samba wrappers
+ */
+int memcmp_const_time(const void *s1, const void *s2, size_t n) {
+
+  return memcmp(s1, s2, n);
+
+}
+
+bool strcsequal(const void *s1, const void *s2) {
+
+  if (s1 == s2) { return true; }
+  if (!s1 || !s2) { return false; }
+  return (strcmp(s1, s2) == 0);
+
+}
+
+/* bcmp/memcmp BSD flavors, similar to CRYPTO_memcmp */
+
+int timingsafe_bcmp(const void *mem1, const void *mem2, size_t len) {
+
+  return bcmp(mem1, mem2, len);
+
+}
+
+int timingsafe_memcmp(const void *mem1, const void *mem2, size_t len) {
+
+  return memcmp(mem1, mem2, len);
+
+}
+
+/* Init code to open the output file (or default to stderr). */
+
+__attribute__((constructor)) void __tokencap_init(void) {
+
+  u8 *fn = getenv("AFL_TOKEN_FILE");
+  if (fn) __tokencap_out_file = open(fn, O_RDWR | O_CREAT | O_APPEND, 0655);
+  if (__tokencap_out_file == -1) __tokencap_out_file = STDERR_FILENO;
+  __tokencap_pid = getpid();
+
+#ifdef RTLD_NEXT
+  __libc_strcmp = dlsym(RTLD_NEXT, "strcmp");
+  __libc_strncmp = dlsym(RTLD_NEXT, "strncmp");
+  __libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp");
+  __libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp");
+  __libc_memcmp = dlsym(RTLD_NEXT, "memcmp");
+  __libc_bcmp = dlsym(RTLD_NEXT, "bcmp");
+  __libc_strstr = dlsym(RTLD_NEXT, "strstr");
+  __libc_strcasestr = dlsym(RTLD_NEXT, "strcasestr");
+  __libc_memmem = dlsym(RTLD_NEXT, "memmem");
+#endif
+
+}
+
+/* closing as best as we can the tokens file */
+__attribute__((destructor)) void __tokencap_shutdown(void) {
+
+  if (__tokencap_out_file != STDERR_FILENO) close(__tokencap_out_file);
+
+}
+
diff --git a/utils/persistent_mode/Makefile b/utils/persistent_mode/Makefile
new file mode 100644
index 00000000..e348c46c
--- /dev/null
+++ b/utils/persistent_mode/Makefile
@@ -0,0 +1,10 @@
+all:
+	../../afl-clang-fast -o persistent_demo persistent_demo.c
+	../../afl-clang-fast -o persistent_demo_new persistent_demo_new.c
+	AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -o test-instr test-instr.c
+
+document:
+	AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c
+
+clean:
+	rm -f persistent_demo persistent_demo_new test-instr
diff --git a/utils/persistent_mode/persistent_demo.c b/utils/persistent_mode/persistent_demo.c
new file mode 100644
index 00000000..f5e43728
--- /dev/null
+++ b/utils/persistent_mode/persistent_demo.c
@@ -0,0 +1,118 @@
+/*
+   american fuzzy lop++ - persistent mode example
+   --------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2015 Google Inc. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   This file demonstrates the high-performance "persistent mode" that may be
+   suitable for fuzzing certain fast and well-behaved libraries, provided that
+   they are stateless or that their internal state can be easily reset
+   across runs.
+
+   To make this work, the library and this shim need to be compiled in LLVM
+   mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <limits.h>
+
+/* Main entry point. */
+
+/* To ensure checks are not optimized out it is recommended to disable
+   code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC            optimize("O0")
+
+int main(int argc, char **argv) {
+
+  ssize_t len;                               /* how much input did we read? */
+  char buf[100]; /* Example-only buffer, you'd replace it with other global or
+                    local variables appropriate for your use case. */
+
+  /* The number passed to __AFL_LOOP() controls the maximum number of
+     iterations before the loop exits and the program is allowed to
+     terminate normally. This limits the impact of accidental memory leaks
+     and similar hiccups. */
+
+  __AFL_INIT();
+  while (__AFL_LOOP(UINT_MAX)) {
+
+    /*** PLACEHOLDER CODE ***/
+
+    /* STEP 1: Fully re-initialize all critical variables. In our example, this
+               involves zeroing buf[], our input buffer. */
+
+    memset(buf, 0, 100);
+
+    /* STEP 2: Read input data. When reading from stdin, no special preparation
+               is required. When reading from a named file, you need to close
+               the old descriptor and reopen the file first!
+
+               Beware of reading from buffered FILE* objects such as stdin. Use
+               raw file descriptors or call fopen() / fdopen() in every pass. */
+
+    len = read(0, buf, 100);
+
+    /* STEP 3: This is where we'd call the tested library on the read data.
+               We just have some trivial inline code that faults on 'foo!'. */
+
+    /* do we have enough data? */
+    if (len < 8) continue;
+
+    if (buf[0] == 'f') {
+
+      printf("one\n");
+      if (buf[1] == 'o') {
+
+        printf("two\n");
+        if (buf[2] == 'o') {
+
+          printf("three\n");
+          if (buf[3] == '!') {
+
+            printf("four\n");
+            if (buf[4] == '!') {
+
+              printf("five\n");
+              if (buf[5] == '!') {
+
+                printf("six\n");
+                abort();
+
+              }
+
+            }
+
+          }
+
+        }
+
+      }
+
+    }
+
+    /*** END PLACEHOLDER CODE ***/
+
+  }
+
+  /* Once the loop is exited, terminate normally - AFL will restart the process
+     when this happens, with a clean slate when it comes to allocated memory,
+     leftover file descriptors, etc. */
+
+  return 0;
+
+}
+
diff --git a/utils/persistent_mode/persistent_demo_new.c b/utils/persistent_mode/persistent_demo_new.c
new file mode 100644
index 00000000..285f50aa
--- /dev/null
+++ b/utils/persistent_mode/persistent_demo_new.c
@@ -0,0 +1,123 @@
+/*
+   american fuzzy lop++ - persistent mode example
+   --------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2015 Google Inc. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+
+   This file demonstrates the high-performance "persistent mode" that may be
+   suitable for fuzzing certain fast and well-behaved libraries, provided that
+   they are stateless or that their internal state can be easily reset
+   across runs.
+
+   To make this work, the library and this shim need to be compiled in LLVM
+   mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <limits.h>
+
+/* this lets the source compile without afl-clang-fast/lto */
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+
+ssize_t       fuzz_len;
+unsigned char fuzz_buf[1024000];
+
+  #define __AFL_FUZZ_TESTCASE_LEN fuzz_len
+  #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
+  #define __AFL_FUZZ_INIT() void sync(void);
+  #define __AFL_LOOP(x) \
+    ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0)
+  #define __AFL_INIT() sync()
+
+#endif
+
+__AFL_FUZZ_INIT();
+
+/* Main entry point. */
+
+/* To ensure checks are not optimized out it is recommended to disable
+   code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC            optimize("O0")
+
+int main(int argc, char **argv) {
+
+  ssize_t        len;                        /* how much input did we read? */
+  unsigned char *buf;                        /* test case buffer pointer    */
+
+  /* The number passed to __AFL_LOOP() controls the maximum number of
+     iterations before the loop exits and the program is allowed to
+     terminate normally. This limits the impact of accidental memory leaks
+     and similar hiccups. */
+
+  __AFL_INIT();
+  buf = __AFL_FUZZ_TESTCASE_BUF;  // this must be assigned before __AFL_LOOP!
+
+  while (__AFL_LOOP(UINT_MAX)) {  // increase if you have good stability
+
+    len = __AFL_FUZZ_TESTCASE_LEN;  // do not use the macro directly in a call!
+
+    // fprintf(stderr, "input: %zd \"%s\"\n", len, buf);
+
+    /* do we have enough data? */
+    if (len < 8) continue;
+
+    if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n");
+
+    if (buf[0] == 'f') {
+
+      printf("one\n");
+      if (buf[1] == 'o') {
+
+        printf("two\n");
+        if (buf[2] == 'o') {
+
+          printf("three\n");
+          if (buf[3] == '!') {
+
+            printf("four\n");
+            if (buf[4] == '!') {
+
+              printf("five\n");
+              if (buf[5] == '!') {
+
+                printf("six\n");
+                abort();
+
+              }
+
+            }
+
+          }
+
+        }
+
+      }
+
+    }
+
+    /*** END PLACEHOLDER CODE ***/
+
+  }
+
+  /* Once the loop is exited, terminate normally - AFL will restart the process
+     when this happens, with a clean slate when it comes to allocated memory,
+     leftover file descriptors, etc. */
+
+  return 0;
+
+}
+
diff --git a/utils/persistent_mode/test-instr.c b/utils/persistent_mode/test-instr.c
new file mode 100644
index 00000000..6da511de
--- /dev/null
+++ b/utils/persistent_mode/test-instr.c
@@ -0,0 +1,75 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+
+__AFL_FUZZ_INIT();
+
+/* To ensure checks are not optimized out it is recommended to disable
+   code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC            optimize("O0")
+
+int main(int argc, char **argv) {
+
+  __AFL_INIT();
+  unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
+
+  while (__AFL_LOOP(UINT_MAX)) {  // if you have 100% stability
+
+    unsigned int len = __AFL_FUZZ_TESTCASE_LEN;
+
+#ifdef _AFL_DOCUMENT_MUTATIONS
+    static unsigned int counter = 0;
+    char                fn[32];
+    sprintf(fn, "%09u:test-instr", counter);
+    int fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    if (fd_doc >= 0) {
+
+      if (write(fd_doc, buf, len) != __afl_fuzz_len) {
+
+        fprintf(stderr, "write of mutation file failed: %s\n", fn);
+        unlink(fn);
+
+      }
+
+      close(fd_doc);
+
+    }
+
+    counter++;
+#endif
+
+    // fprintf(stderr, "len: %u\n", len);
+
+    if (!len) continue;
+
+    if (buf[0] == '0')
+      printf("Looks like a zero to me!\n");
+    else if (buf[0] == '1')
+      printf("Pretty sure that is a one!\n");
+    else
+      printf("Neither one or zero? How quaint!\n");
+
+  }
+
+  return 0;
+
+}
+
diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md
new file mode 100755
index 00000000..641a6e85
--- /dev/null
+++ b/utils/qbdi_mode/README.md
@@ -0,0 +1,199 @@
+# qbdi-based binary-only instrumentation for afl-fuzz
+
+## 1) Introduction
+
+The code in ./qbdi_mode allows you to build a standalone feature that
+using the QBDI framework to fuzz android native library.
+
+
+## 2) Build
+
+First download the Android NDK
+
+```
+https://developer.android.com/ndk/downloads
+https://dl.google.com/android/repository/android-ndk-r20-linux-x86_64.zip
+```
+
+Then unzip it and build the standalone-toolchain
+For x86_64 standalone-toolchain
+
+```
+unzip android-ndk-r20-linux-x86_64.zip
+cd android-ndk-r20/
+./build/tools/make_standalone_toolchain.py --arch x86_64 --api 21 --install-dir ../android-standalone-toolchain-x86_64
+```
+
+For x86 standalone-toolchain
+
+```
+./build/tools/make_standalone_toolchain.py --arch x86 --api 21 --install-dir ../android-standalone-toolchain-x86
+```
+
+In alternative you can also use the prebuilt toolchain, in that case make sure to set the proper CC and CXX env variables because there are many different compilers for each API version in the prebuilt toolchain.
+
+For example:
+
+```
+export STANDALONE_TOOLCHAIN_PATH=~/Android/Sdk/ndk/20.1.5948944/toolchains/llvm/prebuilt/linux-x86_64/
+export CC=x86_64-linux-android21-clang
+export CXX=x86_64-linux-android21-clang++
+```
+
+Then download the QBDI SDK from website
+
+```
+https://qbdi.quarkslab.com/
+```
+
+For Android x86_64
+```
+https://github.com/QBDI/QBDI/releases/download/v0.7.0/QBDI-0.7.0-android-X86_64.tar.gz
+```
+
+Then decompress the sdk
+
+```
+mkdir android-qbdi-sdk-x86_64
+cp QBDI-0.7.0-android-X86_64.tar.gz android-qbdi-sdk-x86_64/
+cd android-qbdi-sdk-x86_64/
+tar xvf QBDI-0.7.0-android-X86_64.tar.gz
+```
+
+Now set the `STANDALONE_TOOLCHAIN_PATH` to the path of standalone-toolchain 
+
+```
+export STANDALONE_TOOLCHAIN_PATH=/home/hac425/workspace/android-standalone-toolchain-x86_64
+```
+
+set the `QBDI_SDK_PATH` to the path of QBDI SDK
+
+```
+export QBDI_SDK_PATH=/home/hac425/workspace/AFLplusplus/qbdi_mode/android-qbdi-sdk-x86_64/
+```
+
+Then run the build.sh
+
+```
+./build.sh x86_64
+```
+
+this could build the afl-fuzz and also the qbdi template for android x86_64
+
+
+### Example
+
+The demo-so.c is an vulnerable library, it has a function for test
+
+```c
+int target_func(char *buf, int size) {
+
+  printf("buffer:%p, size:%p\n", buf, size);
+  switch (buf[0]) {
+
+    case 1:
+      puts("222");
+      if (buf[1] == '\x44') {
+
+        puts("null ptr deference");
+        *(char *)(0) = 1;
+
+      }
+
+      break;
+    case 0xff:
+      if (buf[2] == '\xff') {
+
+        if (buf[1] == '\x44') {
+
+          puts("crash....");
+          *(char *)(0xdeadbeef) = 1;
+
+        }
+
+      }
+
+      break;
+    default: puts("default action"); break;
+
+  }
+
+  return 1;
+
+}
+```
+
+This could be build to `libdemo.so`.
+
+Then we should load the library in template.cpp and find the `target` function address.
+```c
+    void *handle = dlopen(lib_path, RTLD_LAZY);
+	..........................................
+	..........................................
+	..........................................
+    p_target_func = (target_func)dlsym(handle, "target_func");
+```
+
+then we read the data from file and call the function in `fuzz_func`
+
+```c
+QBDI_NOINLINE int fuzz_func() {
+
+  if (afl_setup()) { afl_forkserver(); }
+
+  /* Read the input from file */
+  unsigned long len = 0;
+  char *        data = read_file(input_pathname, &len);
+
+  /* Call the target function with the input data */
+  p_target_func(data, len);
+  return 1;
+
+}
+```
+
+Just compile it
+```
+./build.sh x86_64
+```
+
+Then push the `afl-fuzz`, `loader`, `libdemo.so`, the `libQBDI.so` from the QBDI SDK and the `libc++_shared.so` from android-standalone-toolchain to android device
+
+```
+adb push afl-fuzz /data/local/tmp
+adb push libdemo.so /data/local/tmp
+adb push loader /data/local/tmp
+adb push android-qbdi-sdk-x86_64/usr/local/lib/libQBDI.so /data/local/tmp
+adb push ../../android-standalone-toolchain-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so
+/data/local/tmp
+```
+
+In android adb shell, run the loader to test if it runs
+```
+cd /data/local/tmp
+export LD_LIBRARY_PATH=/data/local/tmp
+mkdir in
+echo 0000 > in/1
+./loader libdemo.so in/1
+p_target_func:0x716d96a98600
+	offset:0x600
+	offset:0x580
+buffer:0x716d96609050, size:0x5
+	offset:0x628
+	offset:0x646
+	offset:0x64b
+	offset:0x65c
+	offset:0x6df
+	offset:0x590
+default action
+	offset:0x6eb
+```
+
+Now run `afl-fuzz` to fuzz the demo library
+
+```
+./afl-fuzz -i in -o out -- ./loader /data/local/tmp/libdemo.so @@
+```
+
+![screen1](assets/screen1.png)
+
diff --git a/utils/qbdi_mode/assets/screen1.png b/utils/qbdi_mode/assets/screen1.png
new file mode 100644
index 00000000..3cf1cb76
--- /dev/null
+++ b/utils/qbdi_mode/assets/screen1.png
Binary files differdiff --git a/utils/qbdi_mode/build.sh b/utils/qbdi_mode/build.sh
new file mode 100755
index 00000000..2527bd26
--- /dev/null
+++ b/utils/qbdi_mode/build.sh
@@ -0,0 +1,57 @@
+
+if [ -z ${STANDALONE_TOOLCHAIN_PATH} ]; then
+    echo "please set the android-standalone-toolchain path in STANDALONE_TOOLCHAIN_PATH environmental variable" 
+    echo "for example: "
+    echo "    export STANDALONE_TOOLCHAIN_PATH=/home/android-standalone-toolchain-21/" 
+    exit
+fi
+
+if [ -z ${QBDI_SDK_PATH} ]; then
+    echo "please set the qbdi sdk path in QBDI_SDK_PATH environmental variable" 
+    echo "for example: "
+    echo "    export QBDI_SDK_PATH=/home/QBDI-Android/" 
+    exit
+fi
+
+
+
+if [ "$1" = "x86" ]; then
+  echo "build x86 qbdi"
+  compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/"
+  if [ -z ${CC} ]; then
+      export CC=i686-linux-android-gcc
+  fi
+  if [ -z ${CXX} ]; then
+      export CXX=i686-linux-android-g++
+  fi
+elif [ "$1" = "x86_64" ]; then
+    echo "build x86_64 qbdi"
+    compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/"
+    if [ -z ${CC} ]; then
+        export CC=x86_64-linux-android-gcc
+    fi
+    if [ -z ${CXX} ]; then
+        export CXX=x86_64-linux-android-g++
+    fi
+else
+    echo "usage: ./build.sh arch[x86, x86_64]"
+    exit
+fi
+
+
+CFLAGS="-I${QBDI_SDK_PATH}/usr/local/include/ -L${QBDI_SDK_PATH}/usr/local/lib/"
+
+echo "[+] Building the QBDI template"
+# build the qbdi template 
+${compiler_prefix}${CXX} -o loader template.cpp -lQBDI -ldl -w  -g ${CFLAGS}
+
+echo "[+] Building the demo library"
+# build the demo share library
+${compiler_prefix}${CC} -shared -o libdemo.so demo-so.c -w -g
+
+echo "[+] Building afl-fuzz for Android"
+# build afl-fuzz
+cd ../..
+${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-*.c src/afl-fuzz.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o utils/qbdi_mode/afl-fuzz  -ldl -w
+
+echo "[+] All done. Enjoy!"
diff --git a/utils/qbdi_mode/demo-so.c b/utils/qbdi_mode/demo-so.c
new file mode 100755
index 00000000..dd367036
--- /dev/null
+++ b/utils/qbdi_mode/demo-so.c
@@ -0,0 +1,41 @@
+#include <stdio.h>

+

+// gcc -shared -o libdemo.so demo-so.c -w

+int target_func(char *buf, int size) {

+
+  printf("buffer:%p, size:%p\n", buf, size);

+  switch (buf[0]) {

+
+    case 1:

+      puts("222");

+      if (buf[1] == '\x44') {

+
+        puts("null ptr deference");

+        *(char *)(0) = 1;

+
+      }

+

+      break;

+    case 0xff:

+      if (buf[2] == '\xff') {

+
+        if (buf[1] == '\x44') {

+
+          puts("crash....");

+          *(char *)(0xdeadbeef) = 1;

+
+        }

+
+      }

+

+      break;

+    default:

+      puts("default action");

+      break;

+
+  }

+

+  return 1;

+
+}

+
diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp
new file mode 100755
index 00000000..b2066cc8
--- /dev/null
+++ b/utils/qbdi_mode/template.cpp
@@ -0,0 +1,251 @@
+#include <iostream>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#ifdef __ANDROID__
+  #include "../include/android-ashmem.h"
+#endif
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "../config.h"
+
+#include <QBDI.h>
+
+/* NeverZero */
+
+#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
+  #define INC_AFL_AREA(loc)           \
+    asm volatile(                     \
+        "incb (%0, %1, 1)\n"          \
+        "adcb $0, (%0, %1, 1)\n"      \
+        : /* no out */                \
+        : "r"(afl_area_ptr), "r"(loc) \
+        : "memory", "eax")
+#else
+  #define INC_AFL_AREA(loc) afl_area_ptr[loc]++
+#endif
+
+using namespace QBDI;
+
+typedef int (*target_func)(char *buf, int size);
+
+static const size_t      STACK_SIZE = 0x100000;  // 1MB
+static const QBDI::rword FAKE_RET_ADDR = 0x40000;
+target_func              p_target_func = NULL;
+rword                    module_base = 0;
+rword                    module_end = 0;
+static unsigned char
+    dummy[MAP_SIZE];         /* costs MAP_SIZE but saves a few instructions */
+unsigned char *afl_area_ptr = NULL;           /* Exported for afl_gen_trace */
+
+unsigned long afl_prev_loc = 0;
+
+char input_pathname[PATH_MAX];
+
+/* Set up SHM region and initialize other stuff. */
+
+int afl_setup(void) {
+
+  char *id_str = getenv(SHM_ENV_VAR);
+  int   shm_id;
+  if (id_str) {
+
+    shm_id = atoi(id_str);
+    afl_area_ptr = (unsigned char *)shmat(shm_id, NULL, 0);
+    if (afl_area_ptr == (void *)-1) return 0;
+    memset(afl_area_ptr, 0, MAP_SIZE);
+
+  }
+
+  return 1;
+
+}
+
+/* Fork server logic, invoked once we hit _start. */
+static void afl_forkserver() {
+
+  static unsigned char tmp[4];
+  pid_t                child_pid;
+
+  if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+
+  while (1) {
+
+    int status;
+    u32 was_killed;
+    // wait for afl-fuzz
+    if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2);
+
+    child_pid = fork();
+    if (child_pid < 0) exit(4);
+
+    if (!child_pid) {
+
+      // child return to execute code
+      close(FORKSRV_FD);
+      close(FORKSRV_FD + 1);
+      return;
+
+    }
+
+    // write child pid to afl-fuzz
+    if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5);
+
+    // wait child stop
+    if (waitpid(child_pid, &status, 0) < 0) exit(6);
+
+    // send child stop status to afl-fuzz
+    if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7);
+
+  }
+
+}
+
+void afl_maybe_log(unsigned long cur_loc) {
+
+  if (afl_area_ptr == NULL) { return; }
+  unsigned long afl_idx = cur_loc ^ afl_prev_loc;
+  afl_idx &= MAP_SIZE - 1;
+  INC_AFL_AREA(afl_idx);
+  afl_prev_loc = cur_loc >> 1;
+
+}
+
+char *read_file(char *path, unsigned long *length) {
+
+  unsigned long len;
+  char *        buf;
+
+  FILE *fp = fopen(path, "rb");
+  fseek(fp, 0, SEEK_END);
+  len = ftell(fp);
+  buf = (char *)malloc(len);
+  rewind(fp);
+  fread(buf, 1, len, fp);
+  fclose(fp);
+  *length = len;
+  return buf;
+
+}
+
+QBDI_NOINLINE int fuzz_func() {
+
+  if (afl_setup()) { afl_forkserver(); }
+
+  unsigned long len = 0;
+  char *        data = read_file(input_pathname, &len);
+
+  // printf("In fuzz_func\n");
+  p_target_func(data, len);
+  return 1;
+
+}
+
+static QBDI::VMAction bbcallback(QBDI::VMInstanceRef  vm,
+                                 const QBDI::VMState *state,
+                                 QBDI::GPRState *     gprState,
+                                 QBDI::FPRState *fprState, void *data) {
+
+  // errno = SAVED_ERRNO;
+
+#ifdef __x86_64__
+  unsigned long pc = gprState->rip;
+#elif defined(i386)
+  unsigned long pc = gprState->eip;
+#elif defined(__arm__)
+  unsigned long pc = gprState->pc;
+#endif
+
+  // just log the module path
+  if (pc >= module_base && pc <= module_end) {
+
+    unsigned long offset = pc - module_base;
+    printf("\toffset:%p\n", offset);
+    afl_maybe_log(offset);
+
+  }
+
+  return QBDI::VMAction::CONTINUE;
+
+}
+
+int main(int argc, char **argv) {
+
+  if (argc < 3) {
+
+    puts("usage: ./loader library_path input_file_path");
+    exit(0);
+
+  }
+
+  const char *lib_path;
+  lib_path = argv[1];
+  strcpy(input_pathname, argv[2]);
+  void *handle = dlopen(lib_path, RTLD_LAZY);
+
+  if (handle == nullptr) {
+
+    perror("Cannot load library");
+    exit(EXIT_FAILURE);
+
+  }
+
+  const char *lib_name = lib_path;
+  if (strrchr(lib_name, '/') != nullptr) lib_name = strrchr(lib_name, '/') + 1;
+
+  // printf("library name:%s\n", lib_name);
+  // load library module address for log path
+  for (MemoryMap &map : getCurrentProcessMaps()) {
+
+    // printf("module:%s\n", map.name.c_str());
+    if ((map.permission & PF_EXEC) &&
+        strstr(map.name.c_str(), lib_name) != NULL) {
+
+      module_base = map.range.start;
+      module_end = map.range.end;
+
+    }
+
+  }
+
+  if (module_base == 0) {
+
+    std::cerr << "Fail to find base address" << std::endl;
+    return -1;
+
+  }
+
+  // printf("module base:%p, module end:%p\n", module_base, module_end);
+  p_target_func = (target_func)dlsym(handle, "target_func");
+  // p_target_func = (target_func)(module_base + 0x61a);
+  printf("p_target_func:%p\n", p_target_func);
+
+  VM       vm;
+  uint8_t *fakestack = nullptr;
+
+  GPRState *state = vm.getGPRState();
+  allocateVirtualStack(state, STACK_SIZE, &fakestack);
+  vm.addInstrumentedModuleFromAddr(module_base);
+  vm.addInstrumentedModuleFromAddr((rword)&main);
+
+  vm.addVMEventCB(BASIC_BLOCK_ENTRY, bbcallback, nullptr);
+
+  // QBDI::simulateCall(state, FAKE_RET_ADDR);
+  // vm.run((rword)&fuzz_func, (rword)FAKE_RET_ADDR);
+
+  rword ret;
+  vm.call(&ret, (rword)&fuzz_func, {});
+
+  return 0;
+
+}
+
diff --git a/utils/qemu_persistent_hook/Makefile b/utils/qemu_persistent_hook/Makefile
new file mode 100644
index 00000000..85db1b46
--- /dev/null
+++ b/utils/qemu_persistent_hook/Makefile
@@ -0,0 +1,6 @@
+all:
+	$(CC) -no-pie test.c -o test
+	$(CC) -fPIC -shared read_into_rdi.c -o read_into_rdi.so
+
+clean:
+	rm -rf in out test read_into_rdi.so
diff --git a/utils/qemu_persistent_hook/README.md b/utils/qemu_persistent_hook/README.md
new file mode 100644
index 00000000..3f908c22
--- /dev/null
+++ b/utils/qemu_persistent_hook/README.md
@@ -0,0 +1,19 @@
+# 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
+```
diff --git a/utils/qemu_persistent_hook/read_into_rdi.c b/utils/qemu_persistent_hook/read_into_rdi.c
new file mode 100644
index 00000000..f4a8ae59
--- /dev/null
+++ b/utils/qemu_persistent_hook/read_into_rdi.c
@@ -0,0 +1,34 @@
+#include "../../qemu_mode/qemuafl/qemuafl/api.h"
+
+#include <stdio.h>
+#include <string.h>
+
+void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
+                         uint8_t *input_buf, uint32_t input_buf_len) {
+\
+#define g2h(x) ((void *)((unsigned long)(x) + guest_base))
+#define h2g(x) ((uint64_t)(x)-guest_base)
+
+  // In this example the register RDI is pointing to the memory location
+  // of the target buffer, and the length of the input is in RSI.
+  // This can be seen with a debugger, e.g. gdb (and "disass main")
+
+  printf("Placing input into 0x%lx\n", regs->rdi);
+
+  if (input_buf_len > 1024) input_buf_len = 1024;
+  memcpy(g2h(regs->rdi), input_buf, input_buf_len);
+  regs->rsi = 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;
+
+}
+
diff --git a/utils/qemu_persistent_hook/test.c b/utils/qemu_persistent_hook/test.c
new file mode 100644
index 00000000..a0e815dc
--- /dev/null
+++ b/utils/qemu_persistent_hook/test.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+
+int target_func(unsigned char *buf, int size) {
+
+  printf("buffer:%p, size:%d\n", buf, size);
+  switch (buf[0]) {
+
+    case 1:
+      if (buf[1] == '\x44') { puts("a"); }
+      break;
+    case 0xff:
+      if (buf[2] == '\xff') {
+
+        if (buf[1] == '\x44') { puts("b"); }
+
+      }
+
+      break;
+    default:
+      break;
+
+  }
+
+  return 1;
+
+}
+
+char data[1024];
+
+int main() {
+
+  target_func(data, 1024);
+
+}
+
diff --git a/utils/socket_fuzzing/Makefile b/utils/socket_fuzzing/Makefile
new file mode 100644
index 00000000..9476e2d5
--- /dev/null
+++ b/utils/socket_fuzzing/Makefile
@@ -0,0 +1,61 @@
+#
+# american fuzzy lop++ - socket_fuzz
+# ----------------------------------
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS  += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
+#  M32FLAG = -mbe32
+# endif
+#endif
+
+all: socketfuzz32.so socketfuzz64.so
+
+socketfuzz32.so: socketfuzz.c
+	-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz32 build failure (that's fine)"
+
+socketfuzz64.so: socketfuzz.c
+	-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "socketfuzz64 build failure (that's fine)"
+
+install: socketfuzz32.so socketfuzz64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f socketfuzz32.so ]; then set -e; install -m 755 socketfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	if [ -f socketfuzz64.so ]; then set -e; install -m 755 socketfuzz64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+clean:
+	rm -f socketfuzz32.so socketfuzz64.so
diff --git a/utils/socket_fuzzing/README.md b/utils/socket_fuzzing/README.md
new file mode 100644
index 00000000..79f28bea
--- /dev/null
+++ b/utils/socket_fuzzing/README.md
@@ -0,0 +1,11 @@
+# socketfuzz
+
+when you want to fuzz a network service and you can not/do not want to modify
+the source (or just have a binary), then this LD_PRELOAD library will allow
+for sending input to stdin which the target binary will think is coming from
+a network socket.
+
+This is desock_dup.c from the amazing preeny project
+https://github.com/zardus/preeny
+
+It is packaged in afl++ to have it at hand if needed
diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c
new file mode 100644
index 00000000..3ec8383b
--- /dev/null
+++ b/utils/socket_fuzzing/socketfuzz.c
@@ -0,0 +1,110 @@
+/*
+ * This is desock_dup.c from the amazing preeny project
+ * https://github.com/zardus/preeny
+ *
+ * It is packaged in afl++ to have it at hand if needed
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>   //
+#include <sys/socket.h>  //
+#include <sys/stat.h>    //
+#include <fcntl.h>       //
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <poll.h>
+//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: "
+
+//
+// originals
+//
+int (*original_close)(int);
+int (*original_dup2)(int, int);
+__attribute__((constructor)) void preeny_desock_dup_orig() {
+
+  original_close = dlsym(RTLD_NEXT, "close");
+  original_dup2 = dlsym(RTLD_NEXT, "dup2");
+
+}
+
+int close(int sockfd) {
+
+  if (sockfd <= 2) {
+
+    fprintf(stderr, "Info: Disabling close on %d\n", sockfd);
+    return 0;
+
+  } else {
+
+    return original_close(sockfd);
+
+  }
+
+}
+
+int dup2(int old, int new) {
+
+  if (new <= 2) {
+
+    fprintf(stderr, "Info: Disabling dup from %d to %d\n", old, new);
+    return 0;
+
+  } else {
+
+    return original_dup2(old, new);
+
+  }
+
+}
+
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+
+  (void)sockfd;
+  (void)addr;
+  (void)addrlen;
+  fprintf(stderr, "Info: Emulating accept on %d\n", sockfd);
+  return 0;
+
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+
+  (void)sockfd;
+  (void)addr;
+  (void)addrlen;
+  fprintf(stderr, "Info: Emulating bind on port %d\n",
+          ntohs(((struct sockaddr_in *)addr)->sin_port));
+  return 0;
+
+}
+
+int listen(int sockfd, int backlog) {
+
+  (void)sockfd;
+  (void)backlog;
+  return 0;
+
+}
+
+int setsockopt(int sockfd, int level, int optid, const void *optdata,
+               socklen_t optdatalen) {
+
+  (void)sockfd;
+  (void)level;
+  (void)optid;
+  (void)optdata;
+  (void)optdatalen;
+  return 0;
+
+}
+