about summary refs log tree commit diff
path: root/custom_mutators
diff options
context:
space:
mode:
Diffstat (limited to 'custom_mutators')
-rw-r--r--custom_mutators/README.md11
-rw-r--r--custom_mutators/aflpp/Makefile10
-rw-r--r--custom_mutators/aflpp/README.md8
-rw-r--r--custom_mutators/aflpp/aflpp.c90
-rw-r--r--custom_mutators/aflpp/standalone/Makefile10
-rw-r--r--custom_mutators/aflpp/standalone/README.md10
-rw-r--r--custom_mutators/aflpp/standalone/aflpp-standalone.c163
-rw-r--r--custom_mutators/aflpp_tritondse/README.md9
-rw-r--r--custom_mutators/aflpp_tritondse/aflpp_tritondse.py80
-rw-r--r--custom_mutators/examples/README.md3
-rw-r--r--custom_mutators/examples/custom_post_run.c53
-rw-r--r--custom_mutators/examples/elf_header_mutator.c679
-rw-r--r--custom_mutators/examples/example.py5
-rw-r--r--custom_mutators/grammar_mutator/GRAMMAR_VERSION2
m---------custom_mutators/grammar_mutator/grammar_mutator0
-rw-r--r--custom_mutators/symcc/README.md2
-rw-r--r--custom_mutators/symqemu/Makefile14
-rw-r--r--custom_mutators/symqemu/README.md19
-rw-r--r--custom_mutators/symqemu/symqemu.c424
19 files changed, 1581 insertions, 11 deletions
diff --git a/custom_mutators/README.md b/custom_mutators/README.md
index a5a572c0..2d1220b3 100644
--- a/custom_mutators/README.md
+++ b/custom_mutators/README.md
@@ -70,14 +70,17 @@ requires cmake (among other things):
 
 ### libprotobuf Mutators
 
-There are two WIP protobuf projects, that require work to be working though:
+There are three WIP protobuf projects, that require work to be working though:
+
+ASN.1 example:
+[https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator](https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src/mutator)
 
 transforms protobuf raw:
-https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
+[https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
 
 has a transform function you need to fill for your protobuf format, however
 needs to be ported to the updated AFL++ custom mutator API (not much work):
-https://github.com/thebabush/afl-libprotobuf-mutator
+[https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
 
 same as above but is for current AFL++:
-https://github.com/P1umer/AFLplusplus-protobuf-mutator
+[https://github.com/P1umer/AFLplusplus-protobuf-mutator](https://github.com/P1umer/AFLplusplus-protobuf-mutator)
\ No newline at end of file
diff --git a/custom_mutators/aflpp/Makefile b/custom_mutators/aflpp/Makefile
new file mode 100644
index 00000000..8efdf3e4
--- /dev/null
+++ b/custom_mutators/aflpp/Makefile
@@ -0,0 +1,10 @@
+
+CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
+
+all: aflpp-mutator.so
+
+aflpp-mutator.so:	aflpp.c
+	$(CC) $(CFLAGS) -I../../include -I. -shared -o aflpp-mutator.so aflpp.c ../../src/afl-performance.c
+
+clean:
+	rm -f *.o *~ *.so core
diff --git a/custom_mutators/aflpp/README.md b/custom_mutators/aflpp/README.md
new file mode 100644
index 00000000..04d605c1
--- /dev/null
+++ b/custom_mutators/aflpp/README.md
@@ -0,0 +1,8 @@
+# custum mutator: AFL++
+
+this is the AFL++ havoc mutator as a custom mutator module for AFL++.
+
+just type `make` to build
+
+```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/aflpp/aflpp-mutator.so afl-fuzz ...```
+
diff --git a/custom_mutators/aflpp/aflpp.c b/custom_mutators/aflpp/aflpp.c
new file mode 100644
index 00000000..0b236f76
--- /dev/null
+++ b/custom_mutators/aflpp/aflpp.c
@@ -0,0 +1,90 @@
+#include "afl-fuzz.h"
+#include "afl-mutations.h"
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  u8          *buf;
+  u32          buf_size;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  (void)seed;
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  if ((data->buf = malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  } else {
+
+    data->buf_size = MAX_FILE;
+
+  }
+
+  data->afl = afl;
+
+  return data;
+
+}
+
+/* here we run the AFL++ mutator, which is the best! */
+
+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,
+                       size_t max_size) {
+
+  if (max_size > data->buf_size) {
+
+    u8 *ptr = realloc(data->buf, max_size);
+
+    if (ptr) {
+
+      return 0;
+
+    } else {
+
+      data->buf = ptr;
+      data->buf_size = max_size;
+
+    }
+
+  }
+
+  u32 havoc_steps = 1 + rand_below(data->afl, 16);
+
+  /* set everything up, costly ... :( */
+  memcpy(data->buf, buf, buf_size);
+
+  /* the mutation */
+  u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
+                               false, true, add_buf, add_buf_size, max_size);
+
+  /* return size of mutated data */
+  *out_buf = data->buf;
+  return out_buf_len;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->buf);
+  free(data);
+
+}
+
diff --git a/custom_mutators/aflpp/standalone/Makefile b/custom_mutators/aflpp/standalone/Makefile
new file mode 100644
index 00000000..f1e99445
--- /dev/null
+++ b/custom_mutators/aflpp/standalone/Makefile
@@ -0,0 +1,10 @@
+
+CFLAGS = -O3 -funroll-loops -fPIC
+
+all: aflpp-standalone
+
+aflpp-standalone:	aflpp-standalone.c
+	$(CC) $(CFLAGS) -I../../../include -I. -o aflpp-standalone aflpp-standalone.c ../../../src/afl-performance.c
+
+clean:
+	rm -f *.o *~ aflpp-standalone core
diff --git a/custom_mutators/aflpp/standalone/README.md b/custom_mutators/aflpp/standalone/README.md
new file mode 100644
index 00000000..a1ffb5f9
--- /dev/null
+++ b/custom_mutators/aflpp/standalone/README.md
@@ -0,0 +1,10 @@
+# AFL++ standalone mutator
+
+this is the AFL++ havoc mutator as a standalone mutator
+
+just type `make` to build.
+
+```
+aflpp-standalone inputfile outputfile [splicefile]
+```
+
diff --git a/custom_mutators/aflpp/standalone/aflpp-standalone.c b/custom_mutators/aflpp/standalone/aflpp-standalone.c
new file mode 100644
index 00000000..3a2cbc2f
--- /dev/null
+++ b/custom_mutators/aflpp/standalone/aflpp-standalone.c
@@ -0,0 +1,163 @@
+#include "afl-fuzz.h"
+#include "afl-mutations.h"
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  u8          *buf;
+  u32          buf_size;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  (void)seed;
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  if ((data->buf = malloc(1024*1024)) == NULL) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  } else {
+
+    data->buf_size = 1024*1024;
+
+  }
+
+  /* fake AFL++ state */
+  data->afl = calloc(1, sizeof(afl_state_t));
+  data->afl->queue_cycle = 1;
+  data->afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+  if (data->afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
+  rand_set_seed(data->afl, getpid());
+
+  return data;
+
+}
+
+/* here we run the AFL++ mutator, which is the best! */
+
+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,
+                       size_t max_size) {
+
+  if (max_size > data->buf_size) {
+
+    u8 *ptr = realloc(data->buf, max_size);
+
+    if (ptr) {
+
+      return 0;
+
+    } else {
+
+      data->buf = ptr;
+      data->buf_size = max_size;
+
+    }
+
+  }
+
+  u32 havoc_steps = 1 + rand_below(data->afl, 16);
+
+  /* set everything up, costly ... :( */
+  memcpy(data->buf, buf, buf_size);
+
+  /* the mutation */
+  u32 out_buf_len = afl_mutate(data->afl, data->buf, buf_size, havoc_steps,
+                               false, true, add_buf, add_buf_size, max_size);
+
+  /* return size of mutated data */
+  *out_buf = data->buf;
+  return out_buf_len;
+
+}
+
+int main(int argc, char *argv[]) {
+
+  if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
+    printf("Syntax: %s [-v] [inputfile [outputfile [splicefile]]]\n\n", argv[0]);
+    printf("Reads a testcase from stdin when no input file (or '-') is specified,\n");
+    printf("mutates according to AFL++'s mutation engine, and write to stdout when '-' or\n");
+    printf("no output filename is given. As an optional third parameter you can give a file\n");
+    printf("for splicing. Maximum input and output length is 1MB.\n");
+    printf("The -v verbose option prints debug output to stderr.\n");
+    return 0;
+  }
+
+  FILE *in = stdin, *out = stdout, *splice = NULL;
+  unsigned char *inbuf = malloc(1024 * 1024), *outbuf, *splicebuf = NULL;
+  int verbose = 0, splicelen = 0;
+
+  if (argc > 1 && strcmp(argv[1], "-v") == 0) {
+    verbose = 1;
+    argc--;
+    argv++;
+    fprintf(stderr, "Verbose active\n");
+  }
+
+  my_mutator_t *data = afl_custom_init(NULL, 0);
+
+  if (argc > 1 && strcmp(argv[1], "-") != 0) {
+    if ((in = fopen(argv[1], "r")) == NULL) {
+      perror(argv[1]);
+      return -1;
+    }
+    if (verbose) fprintf(stderr, "Input: %s\n", argv[1]);
+  }
+
+  size_t inlen = fread(inbuf, 1, 1024*1024, in);
+  
+  if (!inlen) {
+    fprintf(stderr, "Error: empty file %s\n", argv[1] ? argv[1] : "stdin");
+    return -1;
+  }
+
+  if (argc > 2 && strcmp(argv[2], "-") != 0) {
+    if ((out = fopen(argv[2], "w")) == NULL) {
+      perror(argv[2]);
+      return -1;
+    }
+    if (verbose) fprintf(stderr, "Output: %s\n", argv[2]);
+  }
+
+  if (argc > 3) {
+    if ((splice = fopen(argv[3], "r")) == NULL) {
+      perror(argv[3]);
+      return -1;
+    }
+    if (verbose) fprintf(stderr, "Splice: %s\n", argv[3]);
+    splicebuf = malloc(1024*1024);
+    size_t splicelen = fread(splicebuf, 1, 1024*1024, splice);
+    if (!splicelen) {
+      fprintf(stderr, "Error: empty file %s\n", argv[3]);
+      return -1;
+    }
+    if (verbose) fprintf(stderr, "Mutation splice length: %zu\n", splicelen);
+  }
+
+  if (verbose) fprintf(stderr, "Mutation input length: %zu\n", inlen);
+  unsigned int outlen = afl_custom_fuzz(data, inbuf, inlen, &outbuf, splicebuf, splicelen, 1024*1024);
+
+  if (outlen == 0 || !outbuf) {
+    fprintf(stderr, "Error: no mutation data returned.\n");
+    return -1;
+  }
+
+  if (verbose) fprintf(stderr, "Mutation output length: %u\n", outlen);
+
+  if (fwrite(outbuf, 1, outlen, out) != outlen) {
+    fprintf(stderr, "Warning: incomplete write.\n");
+    return -1;
+  }
+  
+  return 0;
+}
diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md
index 8a5dd02b..033655d2 100644
--- a/custom_mutators/aflpp_tritondse/README.md
+++ b/custom_mutators/aflpp_tritondse/README.md
@@ -10,8 +10,13 @@
 ../../afl-cc -o ../../test-instr ../../test-instr.c
 mkdir -p in
 echo aaaa > in/in
-TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
+AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr
 ```
 
 Note that this custom mutator works differently, new finds are synced
-after 10-60 seconds to the fuzzing instance.
+after 10-60 seconds to the fuzzing instance. This is necessary because only
+C/C++ custom mutators have access to the internal AFL++ state.
+
+Note that you should run first with `AFL_DEBUG` for 5-10 minutes and see if
+all important libraries and syscalls are hooked (look at `WARNING` and `CRITICAL`
+output during the run, best use with `AFL_NO_UI=1`)
diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
index e0219f0b..58739696 100644
--- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
+++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py
@@ -22,14 +22,17 @@ config = None
 dse = None
 cycle = 0
 count = 0
+finding = 0
 hashes = set()
 format = SeedFormat.RAW
 
 def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
     global count
     global hashes
+    global finding
     if se.seed.hash not in hashes:
         hashes.add(se.seed.hash)
+        finding = 1
         filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash
         if not os.path.exists(filename):
             if is_debug:
@@ -47,6 +50,59 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState):
     #        file.write(se.seed.content)
 
 
+#def rtn_open(se: SymbolicExecutor, pstate: ProcessState, pc):
+#    """
+#    The open behavior.
+#    """
+#    logging.debug('open hooked')
+#
+#    # Get arguments
+#    arg0 = pstate.get_argument_value(0)  # const char *pathname
+#    flags = pstate.get_argument_value(1)  # int flags
+#    mode = pstate.get_argument_value(2)  # int mode
+#    arg0s = pstate.memory.read_string(arg0)
+#
+#    # Concretize the whole path name
+#    pstate.concretize_memory_bytes(arg0, len(arg0s)+1)  # Concretize the whole string + \0
+#
+#    # We use flags as concrete value
+#    pstate.concretize_argument(1)
+#
+#    # Use the flags to open the file in the write mode.
+#    mode = ""
+#    if (flags & 0xFF) == 0x00:   # O_RDONLY
+#        mode = "r"
+#    elif (flags & 0xFF) == 0x01: # O_WRONLY
+#        mode = "w"
+#    elif (flags & 0xFF) == 0x02: # O_RDWR
+#        mode = "r+"
+#
+#    if (flags & 0x0100): # O_CREAT
+#        mode += "x"
+#    if (flags & 0x0200): # O_APPEND
+#        mode = "a"  # replace completely value
+#
+#    if se.seed.is_file_defined(arg0s) and "r" in mode:  # input file and opened in reading
+#        logging.info(f"opening an input file: {arg0s}")
+#        # Program is opening an input
+#        data = se.seed.get_file_input(arg0s)
+#        filedesc = pstate.create_file_descriptor(arg0s, io.BytesIO(data))
+#        fd = filedesc.id
+#    else:
+#        # Try to open it as a regular file
+#        try:
+#            fd = open(arg0s, mode)  # use the mode here
+#            filedesc = pstate.create_file_descriptor(arg0s, fd)
+#            fd = filedesc.id
+#        except Exception as e:
+#            logging.debug(f"Failed to open {arg0s} {e}")
+#            fd = pstate.minus_one
+#
+#    pstate.write_register("rax", fd)  # write the return value
+#    pstate.cpu.program_counter = pstate.pop_stack_value()  # pop the return value
+#    se.skip_instruction()  # skip the current instruction so that the engine go straight fetching the next instruction
+
+
 def init(seed):
     global config
     global dse
@@ -64,6 +120,10 @@ def init(seed):
         is_debug = True
     except KeyError:
         pass
+    if is_debug:
+        logging.basicConfig(level=logging.WARNING)
+    else:
+        logging.basicConfig(level=logging.CRITICAL)
     try:
         foo = os.environ['AFL_CUSTOM_INFO_OUT']
         out_path = foo + '/../tritondse/queue'
@@ -104,7 +164,7 @@ def init(seed):
         format = SeedFormat.COMPOSITE
     # Now set up TritonDSE
     config = Config(coverage_strategy = CoverageStrategy.PATH,
-                    debug = is_debug,
+    #                debug = is_debug,
                     pipe_stdout = is_debug,
                     pipe_stderr = is_debug,
                     execution_timeout = 1,
@@ -115,10 +175,16 @@ def init(seed):
     dse = SymbolicExplorator(config, prog)
     # Add callbacks.
     dse.callback_manager.register_pre_execution_callback(pre_exec_hook)
+    #dse.callback_manager.register_function_callback("open", rtn_open)
 
 
-#def fuzz(buf, add_buf, max_size):
-#    return b""
+def fuzz(buf, add_buf, max_size):
+    global finding
+    finding = 1
+    while finding == 1:
+      finding = 0
+      dse.step()
+    return b""
 
 
 def queue_new_entry(filename_new_queue, filename_orig_queue):
@@ -141,8 +207,14 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
         dse.add_input_seed(seed)
         # Start exploration!
         #dse.step()
-        dse.explore()
+        #dse.explore()
     pass
 
+
+# we simulate just doing one single fuzz in the custom mutator
+def fuzz_count(buf):
+    return 1
+
+
 def splice_optout():
     pass
diff --git a/custom_mutators/examples/README.md b/custom_mutators/examples/README.md
index 655f7a5e..112db243 100644
--- a/custom_mutators/examples/README.md
+++ b/custom_mutators/examples/README.md
@@ -33,3 +33,6 @@ 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.
+
+elf_header_mutator.c - example ELF header mutator based on 
+ [LibGolf](https://github.com/xcellerator/libgolf/)
diff --git a/custom_mutators/examples/custom_post_run.c b/custom_mutators/examples/custom_post_run.c
new file mode 100644
index 00000000..828216ea
--- /dev/null
+++ b/custom_mutators/examples/custom_post_run.c
@@ -0,0 +1,53 @@
+//
+// This is an example on how to use afl_custom_post_run
+// It executes custom code each time after AFL++ executes the target
+//
+// cc -O3 -fPIC -shared -g -o custom_post_run.so -I../../include custom_post_run.c
+// cd ../..
+// afl-cc -o test-instr test-instr.c
+// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_post_run.so \
+//   afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
+//
+
+
+#include "afl-fuzz.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int 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;
+
+}
+
+void afl_custom_post_run(my_mutator_t *data) {
+
+  printf("hello from afl_custom_post_run\n");
+  return;
+}
+
+
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data);
+
+}
\ No newline at end of file
diff --git a/custom_mutators/examples/elf_header_mutator.c b/custom_mutators/examples/elf_header_mutator.c
new file mode 100644
index 00000000..b985257a
--- /dev/null
+++ b/custom_mutators/examples/elf_header_mutator.c
@@ -0,0 +1,679 @@
+/*
+   AFL++ Custom Mutator for ELF Headers
+   Written by @echel0n <melih.sahin@protonmail.com>
+   based on libgolf.h by @xcellerator
+   $ gcc -O3 -fPIC -shared -o elf_mutator.so -I ~/AFLplusplus/include/
+ */
+#include "afl-fuzz.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <linux/elf.h>
+
+/* EI_ABIVERSION isn't used anymore and elf.h defines EI_PAD to be 0x09 */
+#define EI_ABIVERSION 0x08
+#define EI_PAD 0x09
+/* Define the Architecture and ISA constants to match those in <linux/elf.h> */
+#define X86_64 EM_X86_64
+#define ARM32 EM_ARM
+#define AARCH64 EM_AARCH64
+#define uchar unsigned char
+#define DATA_SIZE 0x100
+
+/*
+ * The ELF and Program headers are different sizes depending on 32- and 64-bit
+ * architectures
+ * taken from libgolf.h
+ */
+#define EHDR_T(x) Elf##x##_Ehdr
+#define PHDR_T(x) Elf##x##_Phdr
+#define EHDR(x) ehdr##x
+#define PHDR(x) phdr##x
+#define GET_EHDR(x) (&(elf_ptr->EHDR(x)));
+#define GET_PHDR(x) (&(elf_ptr->PHDR(x)));
+#define REF_EHDR(b, x) ((Elf##b##_Ehdr *)ehdr)->x
+#define REF_PHDR(b, x) ((Elf##b##_Phdr *)phdr)->x
+int ehdr_size;
+int phdr_size;
+/*
+ * This struct holds the bytes that will be executed, and the size.
+ */
+typedef struct text_segment {
+
+  size_t         text_size;
+  unsigned char *text_segment;
+
+} TextSegment;
+
+// example shellcode that exits
+// taken from libgolf.h
+unsigned char buf[] = {0xb0, 0x3c, 0x31, 0xff, 0x0f, 0x05};
+
+/*
+ * This is the raw ELF file
+ * - EHDR(xx) is the ELF header
+ * - PHDR(xx) is the program header
+ * - text is the text segment
+ * - filename is the name of the golf'd binary
+ * - isa is the target architecture (X86_64, ARM32, AARCH64)
+ * taken from libgolf.h
+ */
+typedef struct rawbinary_t {
+
+  EHDR_T(32) EHDR(32);
+  PHDR_T(32) PHDR(32);
+  EHDR_T(64) EHDR(64);
+  PHDR_T(64) PHDR(64);
+  TextSegment text;
+  char       *filename;
+  int         isa;
+
+} RawBinary;
+
+/*
+ * Copy an E_IDENT array into the corresponding fields in the ELF header
+ * Called by populate_ehdr()
+ * taken from libgolf.h
+ */
+int populate_e_ident(RawBinary *elf_ptr, unsigned char e_ident[]) {
+
+  int i;
+  /* Depending on whether the target ISA is 32- or 64-bit, set e_ident */
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      for (i = 0; i < EI_NIDENT; i++)
+        elf_ptr->EHDR(64).e_ident[i] = e_ident[i];
+      break;
+    case ARM32:
+      for (i = 0; i < EI_NIDENT; i++)
+        elf_ptr->EHDR(32).e_ident[i] = e_ident[i];
+      break;
+    default:
+      exit(1);
+
+  }
+
+  return 0;
+
+}
+
+/*
+ * Copy bytes from buf[] array into text_segment in ELF struct
+ * taken from libgolf.h
+ */
+int copy_text_segment(RawBinary *elf_ptr, unsigned char buf[], int text_size) {
+
+  int i;
+
+  /* Set size of text segment and allocate the buffer */
+  elf_ptr->text.text_size = text_size;
+  elf_ptr->text.text_segment =
+      malloc(elf_ptr->text.text_size * sizeof(unsigned char));
+
+  /* Copy the bytes into the text segment buffer */
+  for (i = 0; i < elf_ptr->text.text_size; i++) {
+
+    elf_ptr->text.text_segment[i] = buf[i];
+
+  }
+
+}
+
+/*
+ * Populate the ELF Header with sane values
+ * Returns a pointer to an EHDR struct
+ * taken from libgolf.h
+ */
+void *populate_ehdr(RawBinary *elf_ptr) {
+
+  /*
+   * Set ehdr_size and phdr_size. Determined by whether target ISA is 32- or
+   * 64-bit.
+   */
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      ehdr_size = sizeof(EHDR_T(64));
+      phdr_size = sizeof(PHDR_T(64));
+      break;
+    case ARM32:
+      ehdr_size = sizeof(EHDR_T(32));
+      phdr_size = sizeof(PHDR_T(32));
+      break;
+    default:
+      exit(1);
+
+  };
+
+  /* Start with the E_IDENT area at the top of the file */
+  unsigned char e_ident[EI_NIDENT] = {0};
+
+  /* Magic Bytes */
+  e_ident[EI_MAG0] = 0x7F;
+  e_ident[EI_MAG1] = 0x45;  // E
+  e_ident[EI_MAG2] = 0x4C;  // L
+  e_ident[EI_MAG3] = 0x46;  // F
+
+  /*
+   * EI_CLASS denotes the architecture:
+   * ELFCLASS32: 0x01
+   * ELFCLASS64: 0x02
+   */
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      e_ident[EI_CLASS] = ELFCLASS64;
+      break;
+    case ARM32:
+      e_ident[EI_CLASS] = ELFCLASS32;
+      break;
+    default:
+      exit(1);
+
+  }
+
+  /*
+   * EI_DATA denotes the endianness:
+   * ELFDATA2LSB:   0x01
+   * ELFDATA2MSB:   0x02
+   */
+  e_ident[EI_DATA] = ELFDATA2LSB;
+
+  /* EI_VERSION is always 0x01 */
+  e_ident[EI_VERSION] = EV_CURRENT;
+
+  /*
+   * EI_OSABI defines the target OS. Ignored by most modern ELF parsers.
+   */
+  e_ident[EI_OSABI] = ELFOSABI_NONE;
+
+  /* EI_ABIVERSION was for sub-classification. Un-defined since Linux 2.6 */
+  e_ident[EI_ABIVERSION] = 0x00;
+
+  /* EI_PAD is currently unused */
+  e_ident[EI_PAD] = 0x00;
+
+  /* Copy the E_IDENT section to the ELF struct */
+  populate_e_ident(elf_ptr, e_ident);
+
+  /*
+   * The remainder of the ELF header following E_IDENT follows.
+   *
+   * ehdr is a pointer to either an Elf32_Edhr, or Elf64_Ehdr struct.
+   */
+  void *ehdr = NULL;
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      ehdr = (&(elf_ptr->EHDR(64)));
+      break;
+    case ARM32:
+      ehdr = (&(elf_ptr->EHDR(32)));
+      break;
+    default:
+      exit(1);
+
+  }
+
+  /*
+   * Depending on whether the ISA is 32- or 64-bit determines the size of
+   * many of the fields in the ELF Header. This switch case deals with it.
+   */
+  switch (elf_ptr->isa) {
+
+    // 64-Bit ISAs
+    case X86_64:
+    case AARCH64:
+      /*
+       * e_type specifies what kind of ELF file this is:
+       * ET_NONE:         0x00    // Unknown Type
+       * ET_REL:          0x01    // Relocatable
+       * ET_EXEC:         0x02    // Executable File
+       * ET_DYN:          0x03    // Shared Object
+       * ET_CORE:         0x04    // Core Dump
+       */
+      REF_EHDR(64, e_type) = ET_EXEC;  // 0x0002
+
+      /* e_machine specifies the target ISA */
+      REF_EHDR(64, e_machine) = elf_ptr->isa;
+
+      /* e_version is always set of 0x01 for the original ELF spec */
+      REF_EHDR(64, e_version) = EV_CURRENT;  // 0x00000001
+
+      /*
+       * e_entry is the memory address of the entry point
+       * Set by set_entry_point() after p_vaddr is set in the phdr
+       */
+      REF_EHDR(64, e_entry) = 0x0;
+
+      /*
+       * e_phoff points to the start of the program header, which
+       * immediately follows the ELF header
+       */
+      REF_EHDR(64, e_phoff) = ehdr_size;
+
+      /* e_shoff points to the start of the section header table */
+      REF_EHDR(64, e_shoff) = 0x00;
+
+      /* e_flags is architecture dependent */
+      REF_EHDR(64, e_flags) = 0x0;
+
+      /* e_ehsize contains the size of the ELF header */
+      REF_EHDR(64, e_ehsize) = ehdr_size;
+
+      /* e_phentsize is the size of the program header */
+      REF_EHDR(64, e_phentsize) = phdr_size;
+
+      /*
+       * e_phnum contains the number of entries in the program header
+       * e_phnum * e_phentsize = size of program header table
+       */
+      REF_EHDR(64, e_phnum) = 0x1;
+
+      /* e_shentsize contains the size of a section header entry */
+      REF_EHDR(64, e_shentsize) = 0x0;
+
+      /*
+       * e_shnum contains the number of entries in the section header
+       * e_shnum * e_shentsize = size of section header table
+       */
+      REF_EHDR(64, e_shnum) = 0x0;
+
+      /*
+       * e_shstrndx contains the index of the section header table that
+       * contains the section names
+       */
+      REF_EHDR(64, e_shstrndx) = 0x0;
+
+      break;
+    // 32-Bit ISAs
+    case ARM32:
+      /*
+       * e_type specifies what kind of ELF file this is:
+       * ET_NONE:         0x00    // Unknown Type
+       * ET_REL:          0x01    // Relocatable
+       * ET_EXEC:         0x02    // Executable File
+       * ET_DYN:          0x03    // Shared Object
+       * ET_CORE:         0x04    // Core Dump
+       */
+      REF_EHDR(32, e_type) = ET_EXEC;  // 0x0002
+
+      /* e_machine specifies the target ISA */
+      REF_EHDR(32, e_machine) = elf_ptr->isa;
+
+      /* e_version is always set of 0x01 for the original ELF spec */
+      REF_EHDR(32, e_version) = EV_CURRENT;  // 0x00000001
+
+      /*
+       * e_entry is the memory address of the entry point
+       * Set by set_entry_point() after p_vaddr is set in the phdr
+       */
+      REF_EHDR(32, e_entry) = 0x0;
+
+      /*
+       * e_phoff points to the start of the program header, which
+       * immediately follows the ELF header
+       */
+      REF_EHDR(32, e_phoff) = ehdr_size;
+
+      /* e_shoff points to the start of the section header table */
+      REF_EHDR(32, e_shoff) = 0x0i;
+
+      /* e_flags is architecture dependent */
+      REF_EHDR(32, e_flags) = 0x0;
+
+      /* e_ehsize contains the size of the ELF header */
+      REF_EHDR(32, e_ehsize) = ehdr_size;
+
+      /* e_phentsize is the size of the program header */
+      REF_EHDR(32, e_phentsize) = phdr_size;
+
+      /*
+       * e_phnum contains the number of entries in the program header
+       * e_phnum * e_phentsize = size of program header table
+       */
+      REF_EHDR(32, e_phnum) = 0x1;
+
+      /* e_shentsize contains the size of a section header entry */
+      REF_EHDR(32, e_shentsize) = 0x0;
+
+      /*
+       * e_shnum contains the number of entries in the section header
+       * e_shnum * e_shentsize = size of section header table
+       */
+      REF_EHDR(32, e_shnum) = 0x0;
+
+      /*
+       * e_shstrndx contains the index of the section header table that
+       * contains the section names
+       */
+      REF_EHDR(32, e_shnum) = 0x0;
+
+      break;
+
+  }
+
+  return ehdr;
+
+}
+
+/*
+ * Populate the program headers with sane values
+ * Returns a pointer to a PHDR struct
+ * taken from libgolf.h
+ */
+void *populate_phdr(RawBinary *elf_ptr) {
+
+  /*
+   * All offsets are relative to the start of the program header (0x40)
+   *
+   * phdr is a pointer to either an Elf32_Phdr, or Elf64_Phdr struct.
+   */
+  void *phdr = NULL;
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      phdr = (&(elf_ptr->PHDR(64)));
+      break;
+    case ARM32:
+      phdr = (&(elf_ptr->PHDR(32)));
+      break;
+    default:
+      exit(1);
+
+  }
+
+  /*
+   * Depending on whether the ISA is 32- or 64-bit determines the size of
+   * many of the fields in the Progra Header. This switch case deals with it.
+   */
+  switch (elf_ptr->isa) {
+
+    // 64-Bit ISAs
+    case X86_64:
+    case AARCH64:
+      /*
+       * p_type identifies what type of segment this is
+       * PT_NULL:         0x0     // Unused
+       * PT_LOAD:         0x1     // Loadable Segment
+       * PT_DYNAMIC:      0x2     // Dynamic Linker Information
+       * PT_INTERP:       0x3     // Interpreter Information
+       * PT_NOTE:         0x4     // Auxiliary Information
+       * PT_SHLIB:        0x5     // Reserved
+       * PT_PHDR:         0x6     // Segment with Program Header
+       * PT_TLS:          0x7     // Thread Local Storage
+       */
+      REF_PHDR(64, p_type) = PT_LOAD;  // 0x1
+
+      /*
+       * p_flags defines permissions for this section
+       * PF_R:    0x4     // Read
+       * PF_W:    0x2     // Write
+       * PF_X:    0x1     // Execute
+       */
+      REF_PHDR(64, p_flags) = PF_R | PF_X;  // 0x5
+
+      /*
+       * p_offset is the offset in the file image (relative to the start
+       * of the program header) for this segment.
+       */
+      REF_PHDR(64, p_offset) = 0x0;
+
+      /*
+       * p_vaddr is the virtual address where this segment should be loaded
+       * p_paddr is for the physical address (unused by System V)
+       */
+      REF_PHDR(64, p_vaddr) = 0x400000;
+      REF_PHDR(64, p_paddr) = 0x400000;
+
+      /*
+       * p_filesz is the size of the segment in the file image
+       * p_memsz is the size of the segment in memory
+       *
+       * Note: p_filesz doesn't have to equal p_memsz
+       */
+      REF_PHDR(64, p_filesz) = elf_ptr->text.text_size;
+      REF_PHDR(64, p_memsz) = elf_ptr->text.text_size;
+
+      break;
+    // 32-Bit ISAs
+    case ARM32:
+      /*
+       * p_type identifies what type of segment this is
+       * PT_NULL:         0x0     // Unused
+       * PT_LOAD:         0x1     // Loadable Segment
+       * PT_DYNAMIC:      0x2     // Dynamic Linker Information
+       * PT_INTERP:       0x3     // Interpreter Information
+       * PT_NOTE:         0x4     // Auxiliary Information
+       * PT_SHLIB:        0x5     // Reserved
+       * PT_PHDR:         0x6     // Segment with Program Header
+       * PT_TLS:          0x7     // Thread Local Storage
+       */
+      REF_PHDR(32, p_type) = PT_LOAD;  // 0x1
+
+      /*
+       * p_flags defines permissions for this section
+       * PF_R:    0x4     // Read
+       * PF_W:    0x2     // Write
+       * PF_X:    0x1     // Execute
+       */
+      REF_PHDR(32, p_flags) = PF_R | PF_X;  // 0x5
+
+      /*
+       * p_offset is the offset in the file image (relative to the start
+       * of the program header) for this segment.
+       */
+      REF_PHDR(32, p_offset) = 0x0;
+
+      /*
+       * p_vaddr is the virtual address where this segment should be loaded
+       * p_paddr is for the physical address (unused by System V)
+       */
+      REF_PHDR(32, p_vaddr) = 0x10000;
+      REF_PHDR(32, p_paddr) = 0x10000;
+
+      /*
+       * p_filesz is the size of the segment in the file image
+       * p_memsz is the size of the segment in memory
+       *
+       * Note: p_filesz doesn't have to equal p_memsz
+       */
+      REF_PHDR(32, p_filesz) = elf_ptr->text.text_size;
+      REF_PHDR(32, p_memsz) = elf_ptr->text.text_size;
+
+      break;
+    default:
+      exit(1);
+
+  }
+
+  /*
+   * p_align is the memory alignment
+   *
+   * Note: p_vaddr = p_offset % p_align
+   */
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+      REF_PHDR(64, p_align) = 0x400000;
+      break;
+    case ARM32:
+      REF_PHDR(32, p_align) = 0x10000;
+      break;
+    case AARCH64:
+      REF_PHDR(64, p_align) = 0x400000;
+      break;
+
+  }
+
+  return phdr;
+
+}
+
+/*
+ * e_entry depends on p_vaddr, so has to be set after populate_ehdr()
+ * and populate_phdr() have been called.
+ * taken from libgolf.h
+ */
+int set_entry_point(RawBinary *elf_ptr) {
+
+  /*
+   * Once the whole ELF file is copied into memory, control is handed to
+   * e_entry. Relative to the process's virtual memory address, the .text
+   * segment will be located immediately after the ELF and program header.
+   *
+   * ehdr and phdr are pointers to the ELF and Program headers respectively.
+   * The switch case casts and assigns them to the correct fields of the ELF
+   * struct, then sets ehdr->e_entry.
+   */
+  void *ehdr, *phdr;
+
+  switch (elf_ptr->isa) {
+
+    case X86_64:
+    case AARCH64:
+      ehdr = GET_EHDR(64);
+      phdr = GET_PHDR(64);
+      REF_EHDR(64, e_entry) = REF_PHDR(64, p_vaddr) + ehdr_size + phdr_size;
+      break;
+    case ARM32:
+      ehdr = GET_EHDR(32);
+      phdr = GET_PHDR(32);
+      REF_EHDR(32, e_entry) = REF_PHDR(32, p_vaddr) + ehdr_size + phdr_size;
+      break;
+    default:
+      exit(1);
+
+  }
+
+  return 0;
+
+}
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  size_t       trim_size_current;
+  int          trimmming_steps;
+  int          cur_step;
+  u8          *mutated_out, *post_process_buf, *trim_buf;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_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;
+
+  }
+
+  if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
+  if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
+  if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
+  data->afl = afl;
+  return data;
+
+}
+
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *in_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) {
+
+  RawBinary  elf_obj;
+  RawBinary *elf = &elf_obj;
+  elf->isa = 62;
+  Elf64_Ehdr *ehdr;
+  Elf64_Phdr *phdr;
+  copy_text_segment(elf, buf, sizeof(buf));
+  ehdr = populate_ehdr(elf);
+  phdr = populate_phdr(elf);
+  set_entry_point(elf);
+
+  size_t mutated_size = ehdr_size + phdr_size + elf->text.text_size;
+  int    pos = 0;
+  // example fields
+  ehdr->e_ident[EI_CLASS] = (uint8_t *)(in_buf + pos++);
+  ehdr->e_ident[EI_DATA] = (uint8_t *)(in_buf + pos++);
+  ehdr->e_ident[EI_VERSION] = (uint8_t *)(in_buf + pos++);
+  ehdr->e_ident[EI_OSABI] = (uint8_t *)(in_buf + pos++);
+  for (int i = 0x8; i < 0x10; ++i) {
+
+    (ehdr->e_ident)[i] = (uint8_t *)(in_buf + pos++);
+
+  }
+
+  ehdr->e_version = (uint32_t *)(in_buf + pos);
+  pos += 4;
+  // sections headers
+  ehdr->e_shoff = (uint64_t *)(in_buf + pos);
+  pos += 8;
+  ehdr->e_shentsize = (uint16_t *)(in_buf + pos);
+  pos += 2;
+  ehdr->e_shnum = (uint16_t *)(in_buf + pos);
+  pos += 2;
+  ehdr->e_shstrndx = (uint16_t *)(in_buf + pos);
+  pos += 2;
+  ehdr->e_flags = (uint32_t *)(in_buf + pos);
+  pos += 4;
+  // physical addr
+  phdr->p_paddr = (uint64_t *)(in_buf + pos);
+  pos += 8;
+  phdr->p_align = (uint64_t *)(in_buf + pos);
+  pos += 8;
+
+  /* mimic GEN_ELF()
+   * Write:
+   * - ELF Header
+   * - Program Header
+   * - Text Segment
+   */
+  memcpy(data->mutated_out, ehdr, ehdr_size);
+  memcpy(data->mutated_out + ehdr_size, phdr, phdr_size);
+  memcpy(data->mutated_out + ehdr_size + phdr_size, elf->text.text_segment,
+         elf->text.text_size);
+
+  *out_buf = data->mutated_out;
+  return mutated_size;
+
+}
+
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->post_process_buf);
+  free(data->mutated_out);
+  free(data->trim_buf);
+  free(data);
+
+}
+
diff --git a/custom_mutators/examples/example.py b/custom_mutators/examples/example.py
index 3a6d22e4..830f302f 100644
--- a/custom_mutators/examples/example.py
+++ b/custom_mutators/examples/example.py
@@ -133,6 +133,11 @@ def fuzz(buf, add_buf, max_size):
 #     @return: The buffer containing the test case after
 #     '''
 #     return buf
+# def post_run():
+#     '''
+#     Called after each time the execution of the target program by AFL++
+#     '''
+#     pass
 #
 # def havoc_mutation(buf, max_size):
 #     '''
diff --git a/custom_mutators/grammar_mutator/GRAMMAR_VERSION b/custom_mutators/grammar_mutator/GRAMMAR_VERSION
index 2568c6a5..3a019448 100644
--- a/custom_mutators/grammar_mutator/GRAMMAR_VERSION
+++ b/custom_mutators/grammar_mutator/GRAMMAR_VERSION
@@ -1 +1 @@
-ff4e5a2
+5ed4f8d
diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator
-Subproject ff4e5a265daf5d88c4a636fb6a2c22b1d733db0
+Subproject 5ed4f8d6e6524df9670af6b411b13031833d67d
diff --git a/custom_mutators/symcc/README.md b/custom_mutators/symcc/README.md
index 364a348e..a6839a37 100644
--- a/custom_mutators/symcc/README.md
+++ b/custom_mutators/symcc/README.md
@@ -5,6 +5,8 @@ This uses the symcc to find new paths into the target.
 Note that this is a just a proof of concept example! It is better to use
 the fuzzing helpers of symcc, symqemu, Fuzzolic, etc. rather than this.
 
+Also the symqemu custom mutator is better than this.
+
 To use this custom mutator follow the steps in the symcc repository 
 [https://github.com/eurecom-s3/symcc/](https://github.com/eurecom-s3/symcc/) 
 on how to build symcc and how to instrument a target binary (the same target
diff --git a/custom_mutators/symqemu/Makefile b/custom_mutators/symqemu/Makefile
new file mode 100644
index 00000000..958aec19
--- /dev/null
+++ b/custom_mutators/symqemu/Makefile
@@ -0,0 +1,14 @@
+
+ifdef DEBUG
+  CFLAGS += -DDEBUG
+endif
+
+all: symqemu-mutator.so
+
+CFLAGS	+= -O3 -funroll-loops
+
+symqemu-mutator.so: symqemu.c
+	$(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c
+
+clean:
+	rm -f symqemu-mutator.so *.o *~ core
diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md
new file mode 100644
index 00000000..c3071afc
--- /dev/null
+++ b/custom_mutators/symqemu/README.md
@@ -0,0 +1,19 @@
+# custum mutator: symqemu
+
+This uses the symcc to find new paths into the target.
+
+## How to build and use
+
+To use this custom mutator follow the steps in the symqemu repository 
+[https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/) 
+on how to build symqemu-x86_x64 and put it in your `PATH`.
+
+Just type `make` to build this custom mutator.
+
+```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...```
+
+## Options
+
+`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones.
+
+`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes.
diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c
new file mode 100644
index 00000000..73a1640a
--- /dev/null
+++ b/custom_mutators/symqemu/symqemu.c
@@ -0,0 +1,424 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "config.h"
+#include "debug.h"
+#include "afl-fuzz.h"
+#include "common.h"
+
+afl_state_t *afl_struct;
+static u32   debug = 0;
+static u32   found_items = 0;
+
+#define SYMQEMU_LOCATION "symqemu"
+
+#define DBG(x...) \
+  if (debug) { fprintf(stderr, x); }
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  u32          all;
+  u32          late;
+  u8          *mutator_buf;
+  u8          *out_dir;
+  u8          *target;
+  u8          *symqemu;
+  u8          *input_file;
+  u32          counter;
+  u32          seed;
+  u32          argc;
+  u8         **argv;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  if (getenv("AFL_DEBUG")) debug = 1;
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  char *path = getenv("PATH");
+  char *exec_name = "symqemu-x86_64";
+  char *token = strtok(path, ":");
+  char  exec_path[4096];
+
+  while (token != NULL && data->symqemu == NULL) {
+
+    snprintf(exec_path, sizeof(exec_path), "%s/%s", token, exec_name);
+    if (access(exec_path, X_OK) == 0) {
+
+      data->symqemu = (u8 *)strdup(exec_path);
+      break;
+
+    }
+
+    token = strtok(NULL, ":");
+
+  }
+
+  if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name);
+  DBG("Found %s\n", data->symqemu);
+
+  if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) {
+
+    WARNF(
+        "the symqemu module is not very effective with "
+        "AFL_CUSTOM_MUTATOR_ONLY.");
+
+  }
+
+  if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
+
+    free(data);
+    perror("mutator_buf alloc");
+    return NULL;
+
+  }
+
+  data->target = getenv("AFL_CUSTOM_INFO_PROGRAM");
+
+  u8 *path_tmp = getenv("AFL_CUSTOM_INFO_OUT");
+  u32 len = strlen(path_tmp) + 32;
+  u8 *symqemu_path = malloc(len);
+  data->out_dir = malloc(len);
+  snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION);
+  snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp);
+
+  (void)mkdir(symqemu_path, 0755);
+  (void)mkdir(data->out_dir, 0755);
+
+  setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
+
+  data->input_file = getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT");
+
+  u8 *tmp = NULL;
+  if ((tmp = getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) && *tmp) {
+
+    int argc = 0, index = 2;
+    for (u32 i = 0; i < strlen(tmp); ++i)
+      if (isspace(tmp[i])) ++argc;
+
+    data->argv = (u8 **)malloc((argc + 4) * sizeof(u8 **));
+    u8 *p = strdup(tmp);
+
+    do {
+
+      data->argv[index] = p;
+      while (*p && !isspace(*p))
+        ++p;
+      if (*p) {
+
+        *p++ = 0;
+        while (isspace(*p))
+          ++p;
+
+      }
+
+      if (strcmp(data->argv[index], "@@") == 0) {
+
+        if (!data->input_file) {
+
+          u32 ilen = strlen(symqemu_path) + 32;
+          data->input_file = malloc(ilen);
+          snprintf(data->input_file, ilen, "%s/.input", symqemu_path);
+
+        }
+
+        data->argv[index] = data->input_file;
+
+      }
+
+      DBG("%d: %s\n", index, data->argv[index]);
+      index++;
+
+    } while (*p);
+
+    data->argv[index] = NULL;
+    data->argc = index;
+
+  } else {
+
+    data->argv = (u8 **)malloc(8 * sizeof(u8 **));
+    data->argc = 2;
+    data->argv[2] = NULL;
+
+  }
+
+  data->argv[0] = data->symqemu;
+  data->argv[1] = data->target;
+  data->afl = afl;
+  data->seed = seed;
+  afl_struct = afl;
+
+  if (getenv("SYMQEMU_ALL")) { data->all = 1; }
+  if (getenv("SYMQEMU_LATE")) { data->late = 1; }
+  if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); }
+
+  DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir,
+      data->target,
+      data->input_file ? (char *)data->input_file : (char *)"<stdin>",
+      data->argc);
+
+  if (debug) {
+
+    fprintf(stderr, "[");
+    for (u32 i = 0; i <= data->argc; ++i)
+      fprintf(stderr, " \"%s\"",
+              data->argv[i] ? (char *)data->argv[i] : "<NULL>");
+    fprintf(stderr, " ]\n");
+
+  }
+
+  return data;
+
+}
+
+/* No need to receive a splicing item */
+void afl_custom_splice_optout(void *data) {
+
+  (void)(data);
+
+}
+
+/* Get unix time in milliseconds */
+
+inline u64 get_cur_time(void) {
+
+  struct timeval  tv;
+  struct timezone tz;
+
+  gettimeofday(&tv, &tz);
+
+  return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
+
+}
+
+u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) {
+
+  if (likely((!afl_struct->queue_cur->favored && !data->all) ||
+             afl_struct->queue_cur->was_fuzzed)) {
+
+    return 0;
+
+  }
+
+  if (likely(data->late)) {
+
+    if (unlikely(get_cur_time() - afl_struct->last_find_time <=
+                 10 * 60 * 1000)) {
+
+      return 0;
+
+    }
+
+  }
+
+  int         pipefd[2];
+  struct stat st;
+
+  if (afl_struct->afl_env.afl_no_ui) {
+
+    ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname);
+
+  }
+
+  if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) &&
+        st.st_size)) {
+
+    PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname);
+
+  }
+
+  if (afl_struct->fsrv.use_stdin) {
+
+    if (pipe(pipefd) == -1) {
+
+      PFATAL(
+          "Couldn't create a pipe for interacting with symqemu child process");
+
+    }
+
+  }
+
+  if (data->input_file) {
+
+    int     fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+    ssize_t s = write(fd, buf, buf_size);
+    close(fd);
+    DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file);
+
+  }
+
+  int pid = fork();
+
+  if (pid == -1) return 0;
+
+  if (likely(pid)) {
+
+    if (!data->input_file || afl_struct->fsrv.use_stdin) {
+
+      close(pipefd[0]);
+
+      if (fcntl(pipefd[1], F_GETPIPE_SZ)) {
+
+        fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
+
+      }
+
+      ck_write(pipefd[1], buf, buf_size, data->input_file);
+
+      close(pipefd[1]);
+
+    }
+
+    pid = waitpid(pid, NULL, 0);
+    DBG("symqemu finished executing!\n");
+
+  } else /* (pid == 0) */ {  // child
+
+    if (afl_struct->fsrv.use_stdin) {
+
+      close(pipefd[1]);
+      dup2(pipefd[0], 0);
+
+    }
+
+    DBG("exec=%s\n", data->target);
+    if (!debug) {
+
+      close(1);
+      close(2);
+      dup2(afl_struct->fsrv.dev_null_fd, 1);
+      dup2(afl_struct->fsrv.dev_null_fd, 2);
+
+    }
+
+    execvp((char *)data->argv[0], (char **)data->argv);
+    fprintf(stderr, "Executing: [");
+    for (u32 i = 0; i <= data->argc; ++i)
+      fprintf(stderr, " \"%s\"",
+              data->argv[i] ? (char *)data->argv[i] : "<NULL>");
+    fprintf(stderr, " ]\n");
+    FATAL("Failed to execute %s %s\n", data->argv[0], data->argv[1]);
+    exit(-1);
+
+  }
+
+  /* back in mother process */
+
+  struct dirent **nl;
+  s32             i, items = scandir(data->out_dir, &nl, NULL, NULL);
+  found_items = 0;
+  char source_name[4096];
+
+  if (items > 0) {
+
+    for (i = 0; i < (u32)items; ++i) {
+
+      // symqemu output files start with a digit
+      if (!isdigit(nl[i]->d_name[0])) continue;
+
+      struct stat st;
+      snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
+               nl[i]->d_name);
+      DBG("file=%s\n", source_name);
+
+      if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
+
+        ++found_items;
+
+      }
+
+      free(nl[i]);
+
+    }
+
+    free(nl);
+
+  }
+
+  DBG("Done, found %u items!\n", found_items);
+
+  return found_items;
+
+}
+
+size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
+                       u8 **out_buf, u8 *add_buf, size_t add_buf_size,
+                       size_t max_size) {
+
+  struct dirent **nl;
+  s32             done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL);
+  char            source_name[4096];
+
+  if (items > 0) {
+
+    for (i = 0; i < (u32)items; ++i) {
+
+      // symqemu output files start with a digit
+      if (!isdigit(nl[i]->d_name[0])) continue;
+
+      struct stat st;
+      snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir,
+               nl[i]->d_name);
+      DBG("file=%s\n", source_name);
+
+      if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
+
+        int fd = open(source_name, O_RDONLY);
+        if (fd < 0) { goto got_an_issue; }
+
+        ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
+        close(fd);
+
+        DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r);
+
+        if (r < 1) { goto got_an_issue; }
+
+        done = 1;
+        --found_items;
+        unlink(source_name);
+
+        *out_buf = data->mutator_buf;
+        return (u32)r;
+
+      }
+
+      free(nl[i]);
+
+    }
+
+    free(nl);
+
+  }
+
+got_an_issue:
+  *out_buf = NULL;
+  return 0;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->mutator_buf);
+  free(data);
+
+}
+