about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvanhauser-thc <vh@thc.org>2023-04-04 15:47:53 +0200
committervanhauser-thc <vh@thc.org>2023-04-04 15:47:53 +0200
commitfcd21256780fd21c55e72e9338b3992c60db22dc (patch)
tree2f800ee67c168b84221ea11bf5ec768a4cf40708
parent635da39bd135b7db3529a4b3b059b85260ce14a5 (diff)
downloadafl++-fcd21256780fd21c55e72e9338b3992c60db22dc.tar.gz
prepare for strategies
-rw-r--r--custom_mutators/aflpp/Makefile10
-rw-r--r--custom_mutators/aflpp/README.md8
-rw-r--r--custom_mutators/aflpp/aflpp.c68
-rw-r--r--include/afl-mutations.h992
-rw-r--r--src/afl-fuzz-one.c165
5 files changed, 1143 insertions, 100 deletions
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..2b69ad9c
--- /dev/null
+++ b/custom_mutators/aflpp/aflpp.c
@@ -0,0 +1,68 @@
+#include "afl-mutations.h"
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  u8          *buf;
+
+} 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;
+
+  }
+
+  data->buf = malloc(MAX_FILE);
+  if (!data->buf) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  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) {
+
+  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);
+
+  /* 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/include/afl-mutations.h b/include/afl-mutations.h
new file mode 100644
index 00000000..43b7927d
--- /dev/null
+++ b/include/afl-mutations.h
@@ -0,0 +1,992 @@
+/* Implementation of afl havoc mutation to be used in AFL++ custom mutators and
+   partially in afl-fuzz itself.
+
+   How to use:
+
+   #include "afl-mutations.h"  // needs afl-fuzz.h
+
+   u32 afl_mutate(afl_state_t *afl, u8 *buf, u32 len, u32t steps, bool is_text,
+                  bool is_exploration, u8 *splice_buf, u32 splice_len);
+
+   Returns:
+     u32 - the length of the mutated data return in *buf. 0 = error
+   Parameters:
+     afl_state_t *afl - the *afl state pointer
+     u8 *buf - the input buffer to mutate which will be mutated into.
+               NOTE: must be of MAX_FILE size!
+     u32 len - the length of the input
+     u32 steps - how many mutations to perform on the input
+     bool is_text - is the target expecting text inputs
+     bool is_exploration - mutate for exploration mode (instead of exploitation)
+     splice_buf - a buffer from another corpus item to splice with.
+                  If NULL then no splicing
+     splice_len - the length of the splice buffer. If 0 then no splicing
+*/
+
+#ifndef _ANDROID_ASHMEM_H
+  #define AFL_MUTATIONS_H
+
+  #include <stdbool.h>
+  #include "afl-fuzz.h"
+
+  #define MUT_STRATEGY_ARRAY_SIZE 256
+
+enum {
+
+  /* 00 */ MUT_FLIPBIT,
+  /* 01 */ MUT_INTERESTING8,
+  /* 02 */ MUT_INTERESTING16,
+  /* 03 */ MUT_INTERESTING16BE,
+  /* 04 */ MUT_INTERESTING32,
+  /* 05 */ MUT_INTERESTING32BE,
+  /* 06 */ MUT_ARITH8_,
+  /* 07 */ MUT_ARITH8,
+  /* 08 */ MUT_ARITH16_,
+  /* 09 */ MUT_ARITH16BE_,
+  /* 10 */ MUT_ARITH16,
+  /* 11 */ MUT_ARITH16BE,
+  /* 12 */ MUT_ARITH32_,
+  /* 13 */ MUT_ARITH32BE_,
+  /* 14 */ MUT_ARITH32,
+  /* 15 */ MUT_ARITH32BE,
+  /* 16 */ MUT_RAND8,
+  /* 17 */ MUT_CLONE_OVERWRITE,
+  /* 18 */ MUT_CLONE_INSERT,
+  /* 19 */ MUT_OVERWRITE_COPY,
+  /* 20 */ MUT_OVERWRITE_FIXED,
+  /* 21 */ MUT_BYTEADD,
+  /* 22 */ MUT_BYTESUB,
+  /* 23 */ MUT_FLIP8,
+  /* 24 */ MUT_SWITCH,
+  /* 25 */ MUT_DEL,
+  /* 26 */ MUT_SHUFFLE,
+  /* 27 */ MUT_DELONE,
+  /* 28 */ MUT_INSERTONE,
+  /* 29 */ MUT_ASCIINUM,
+  /* 30 */ MUT_NEG,
+  /* 31 */ MUT_INSERTASCIINUM,
+  /* 32 */ MUT_EXTRA_OVERWRITE,
+  /* 33 */ MUT_EXTRA_INSERT,
+  /* 34 */ MUT_AUTO_EXTRA_OVERWRITE,
+  /* 35 */ MUT_AUTO_EXTRA_INSERT,
+  /* 36 */ MUT_SPLICE_OVERWRITE,
+  /* 37 */ MUT_SPLICE_INSERT,
+
+  MUT_MAX
+
+};
+
+unsigned int mutation_strategy_exploration_text[MUT_STRATEGY_ARRAY_SIZE] = {};
+unsigned int mutation_strategy_exploration_binary[MUT_STRATEGY_ARRAY_SIZE] = {};
+unsigned int mutation_strategy_exploitation_text[MUT_STRATEGY_ARRAY_SIZE] = {};
+unsigned int mutation_strategy_exploitation_binary[MUT_STRATEGY_ARRAY_SIZE] =
+    {};
+
+unsigned int afl_mutate(afl_state_t *, unsigned char *, unsigned int,
+                        unsigned int, bool, bool, unsigned char *,
+                        unsigned int);
+u32          choose_block_len(afl_state_t *, u32);
+
+/* Helper to choose random block len for block operations in fuzz_one().
+   Doesn't return zero, provided that max_len is > 0. */
+
+inline u32 choose_block_len(afl_state_t *afl, u32 limit) {
+
+  u32 min_value, max_value;
+  u32 rlim = MIN(afl->queue_cycle, (u32)3);
+
+  if (unlikely(!afl->run_over10m)) { rlim = 1; }
+
+  switch (rand_below(afl, rlim)) {
+
+    case 0:
+      min_value = 1;
+      max_value = HAVOC_BLK_SMALL;
+      break;
+
+    case 1:
+      min_value = HAVOC_BLK_SMALL;
+      max_value = HAVOC_BLK_MEDIUM;
+      break;
+
+    default:
+
+      if (likely(rand_below(afl, 10))) {
+
+        min_value = HAVOC_BLK_MEDIUM;
+        max_value = HAVOC_BLK_LARGE;
+
+      } else {
+
+        min_value = HAVOC_BLK_LARGE;
+        max_value = HAVOC_BLK_XL;
+
+      }
+
+  }
+
+  if (min_value >= limit) { min_value = 1; }
+
+  return min_value + rand_below(afl, MIN(max_value, limit) - min_value + 1);
+
+}
+
+unsigned int afl_mutate(afl_state_t *afl, unsigned char *buf, unsigned int len,
+                        unsigned int steps, bool is_text, bool is_exploration,
+                        unsigned char *splice_buf, unsigned int splice_len) {
+
+  if (!buf || !len) { return 0; }
+
+  u32                  *mutation_array;
+  static unsigned char *tmp_buf = NULL;
+
+  if (!tmp_buf) {
+
+    if ((tmp_buf = malloc(MAX_FILE)) == NULL) { return 0; }
+
+  }
+
+  if (is_text) {
+
+    if (is_exploration) {
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploration_text;
+
+    } else {
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploitation_text;
+
+    }
+
+  } else {
+
+    if (is_exploration) {
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploration_binary;
+
+    } else {
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploitation_binary;
+
+    }
+
+  }
+
+  for (unsigned int step = 0; step < steps; ++step) {
+
+  retry_havoc_step:
+
+    u32 r = rand_below(afl, MUT_STRATEGY_ARRAY_SIZE), item;
+
+    switch (mutation_array[r]) {
+
+      case MUT_FLIPBIT: {
+
+        /* Flip a single bit somewhere. Spooky! */
+        u8  bit = rand_below(afl, 8);
+        u32 off = rand_below(afl, len);
+        buf[off] ^= 1 << bit;
+
+        break;
+
+      }
+
+      case MUT_INTERESTING8: {
+
+        /* Set byte to interesting value. */
+
+        item = rand_below(afl, sizeof(interesting_8));
+        buf[rand_below(afl, len)] = interesting_8[item];
+        break;
+
+      }
+
+      case MUT_INTERESTING16: {
+
+        /* Set word to interesting value, little endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        item = rand_below(afl, sizeof(interesting_16) >> 1);
+        *(u16 *)(buf + rand_below(afl, len - 1)) = interesting_16[item];
+
+        break;
+
+      }
+
+      case MUT_INTERESTING16BE: {
+
+        /* Set word to interesting value, big endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        item = rand_below(afl, sizeof(interesting_16) >> 1);
+        *(u16 *)(buf + rand_below(afl, len - 1)) = SWAP16(interesting_16[item]);
+
+        break;
+
+      }
+
+      case MUT_INTERESTING32: {
+
+        /* Set dword to interesting value, little endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        item = rand_below(afl, sizeof(interesting_32) >> 2);
+        *(u32 *)(buf + rand_below(afl, len - 3)) = interesting_32[item];
+
+        break;
+
+      }
+
+      case MUT_INTERESTING32BE: {
+
+        /* Set dword to interesting value, big endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        item = rand_below(afl, sizeof(interesting_32) >> 2);
+        *(u32 *)(buf + rand_below(afl, len - 3)) = SWAP32(interesting_32[item]);
+
+        break;
+
+      }
+
+      case MUT_ARITH8_: {
+
+        /* Randomly subtract from byte. */
+
+        item = 1 + rand_below(afl, ARITH_MAX);
+        buf[rand_below(afl, len)] -= item;
+        break;
+
+      }
+
+      case MUT_ARITH8: {
+
+        /* Randomly add to byte. */
+
+        item = 1 + rand_below(afl, ARITH_MAX);
+        buf[rand_below(afl, len)] += item;
+        break;
+
+      }
+
+      case MUT_ARITH16_: {
+
+        /* Randomly subtract from word, little endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 1);
+        item = 1 + rand_below(afl, ARITH_MAX);
+        *(u16 *)(buf + pos) -= item;
+
+        break;
+
+      }
+
+      case MUT_ARITH16BE_: {
+
+        /* Randomly subtract from word, big endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 1);
+        u16 num = 1 + rand_below(afl, ARITH_MAX);
+        *(u16 *)(buf + pos) = SWAP16(SWAP16(*(u16 *)(buf + pos)) - num);
+
+        break;
+
+      }
+
+      case MUT_ARITH16: {
+
+        /* Randomly add to word, little endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 1);
+        item = 1 + rand_below(afl, ARITH_MAX);
+        *(u16 *)(buf + pos) += item;
+
+        break;
+
+      }
+
+      case MUT_ARITH16BE: {
+
+        /* Randomly add to word, big endian. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 1);
+        u16 num = 1 + rand_below(afl, ARITH_MAX);
+        *(u16 *)(buf + pos) = SWAP16(SWAP16(*(u16 *)(buf + pos)) + num);
+
+        break;
+
+      }
+
+      case MUT_ARITH32_: {
+
+        /* Randomly subtract from dword, little endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 3);
+        item = 1 + rand_below(afl, ARITH_MAX);
+        *(u32 *)(buf + pos) -= item;
+
+        break;
+
+      }
+
+      case MUT_ARITH32BE_: {
+
+        /* Randomly subtract from dword, big endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 3);
+        u32 num = 1 + rand_below(afl, ARITH_MAX);
+        *(u32 *)(buf + pos) = SWAP32(SWAP32(*(u32 *)(buf + pos)) - num);
+
+        break;
+
+      }
+
+      case MUT_ARITH32: {
+
+        /* Randomly add to dword, little endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 3);
+        item = 1 + rand_below(afl, ARITH_MAX);
+        *(u32 *)(buf + pos) += item;
+
+        break;
+
+      }
+
+      case MUT_ARITH32BE: {
+
+        /* Randomly add to dword, big endian. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 pos = rand_below(afl, len - 3);
+        u32 num = 1 + rand_below(afl, ARITH_MAX);
+        *(u32 *)(buf + pos) = SWAP32(SWAP32(*(u32 *)(buf + pos)) + num);
+
+        break;
+
+      }
+
+      case MUT_RAND8: {
+
+        /* 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. */
+
+        u32 pos = rand_below(afl, len);
+        item = 1 + rand_below(afl, 255);
+        buf[pos] ^= item;
+        break;
+
+      }
+
+      case MUT_CLONE_OVERWRITE: {
+
+        if (likely(len + HAVOC_BLK_XL < MAX_FILE)) {
+
+          /* Clone bytes. */
+
+          u32 clone_len = choose_block_len(afl, len);
+          u32 clone_from = rand_below(afl, len - clone_len + 1);
+          u32 clone_to = rand_below(afl, len);
+
+          /* Head */
+
+          memcpy(tmp_buf, buf, clone_to);
+
+          /* Inserted part */
+
+          memcpy(tmp_buf + clone_to, buf + clone_from, clone_len);
+
+          /* Tail */
+          memcpy(tmp_buf + clone_to + clone_len, buf + clone_to,
+                 len - clone_to);
+
+          len += clone_len;
+          memcpy(buf, tmp_buf, len);
+
+        } else if (unlikely(len < 8)) {
+
+          break;
+
+        } else {
+
+          goto retry_havoc_step;
+
+        }
+
+        break;
+
+      }
+
+      case MUT_CLONE_INSERT: {
+
+        if (likely(len + HAVOC_BLK_XL < MAX_FILE)) {
+
+          /* Insert a block of constant bytes (25%). */
+
+          u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL);
+          u32 clone_to = rand_below(afl, len);
+          u32 strat = rand_below(afl, 2);
+          u32 clone_from = clone_to ? clone_to - 1 : 0;
+          item = strat ? rand_below(afl, 256) : buf[clone_from];
+
+          /* Head */
+
+          memcpy(tmp_buf, buf, clone_to);
+
+          /* Inserted part */
+
+          memset(tmp_buf + clone_to, item, clone_len);
+
+          /* Tail */
+          memcpy(tmp_buf + clone_to + clone_len, buf + clone_to,
+                 len - clone_to);
+
+          len += clone_len;
+          memcpy(buf, tmp_buf, len);
+
+        } else if (unlikely(len < 8)) {
+
+          break;
+
+        } else {
+
+          goto retry_havoc_step;
+
+        }
+
+        break;
+
+      }
+
+      case MUT_OVERWRITE_COPY: {
+
+        /* Overwrite bytes with a randomly selected chunk bytes. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 copy_len = choose_block_len(afl, len - 1);
+        u32 copy_from = rand_below(afl, len - copy_len + 1);
+        u32 copy_to = rand_below(afl, len - copy_len + 1);
+
+        if (likely(copy_from != copy_to)) {
+
+          memmove(buf + copy_to, buf + copy_from, copy_len);
+
+        }
+
+        break;
+
+      }
+
+      case MUT_OVERWRITE_FIXED: {
+
+        /* Overwrite bytes with fixed bytes. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 copy_len = choose_block_len(afl, len - 1);
+        u32 copy_to = rand_below(afl, len - copy_len + 1);
+        u32 strat = rand_below(afl, 2);
+        u32 copy_from = copy_to ? copy_to - 1 : 0;
+        item = strat ? rand_below(afl, 256) : buf[copy_from];
+        memset(buf + copy_to, item, copy_len);
+
+        break;
+
+      }
+
+      case MUT_BYTEADD: {
+
+        /* Increase byte by 1. */
+
+        buf[rand_below(afl, len)]++;
+        break;
+
+      }
+
+      case MUT_BYTESUB: {
+
+        /* Decrease byte by 1. */
+
+        buf[rand_below(afl, len)]--;
+        break;
+
+      }
+
+      case MUT_FLIP8: {
+
+        /* Flip byte. */
+
+        buf[rand_below(afl, len)] ^= 0xff;
+        break;
+
+      }
+
+      case MUT_SWITCH: {
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        /* Switch bytes. */
+
+        u32 to_end, switch_to, switch_len, switch_from;
+        switch_from = rand_below(afl, len);
+        do {
+
+          switch_to = rand_below(afl, len);
+
+        } while (unlikely(switch_from == switch_to));
+
+        if (switch_from < switch_to) {
+
+          switch_len = switch_to - switch_from;
+          to_end = len - switch_to;
+
+        } else {
+
+          switch_len = switch_from - switch_to;
+          to_end = len - switch_from;
+
+        }
+
+        switch_len = choose_block_len(afl, MIN(switch_len, to_end));
+
+        /* Backup */
+
+        memcpy(tmp_buf, buf + switch_from, switch_len);
+
+        /* Switch 1 */
+
+        memcpy(buf + switch_from, buf + switch_to, switch_len);
+
+        /* Switch 2 */
+
+        memcpy(buf + switch_to, tmp_buf, switch_len);
+
+        break;
+
+      }
+
+      case MUT_DEL: {
+
+        /* Delete bytes. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        /* Don't delete too much. */
+
+        u32 del_len = choose_block_len(afl, len - 1);
+        u32 del_from = rand_below(afl, len - del_len + 1);
+        memmove(buf + del_from, buf + del_from + del_len,
+                len - del_from - del_len);
+        len -= del_len;
+
+        break;
+
+      }
+
+      case MUT_SHUFFLE: {
+
+        /* Shuffle bytes. */
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 len = choose_block_len(afl, len - 1);
+        u32 off = rand_below(afl, len - len + 1);
+
+        for (u32 i = len - 1; i > 0; i--) {
+
+          u32 j;
+          do {
+
+            j = rand_below(afl, i + 1);
+
+          } while (unlikely(i == j));
+
+          unsigned char temp = buf[off + i];
+          buf[off + i] = buf[off + j];
+          buf[off + j] = temp;
+
+        }
+
+        break;
+
+      }
+
+      case MUT_DELONE: {
+
+        /* Delete bytes. */
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        /* Don't delete too much. */
+
+        u32 del_len = 1;
+        u32 del_from = rand_below(afl, len - del_len + 1);
+        memmove(buf + del_from, buf + del_from + del_len,
+                len - del_from - del_len);
+
+        len -= del_len;
+
+        break;
+
+      }
+
+      case MUT_INSERTONE: {
+
+        if (unlikely(len < 2)) { break; }  // no retry
+
+        u32 clone_len = 1;
+        u32 clone_to = rand_below(afl, len);
+        u32 strat = rand_below(afl, 2);
+        u32 clone_from = clone_to ? clone_to - 1 : 0;
+        item = strat ? rand_below(afl, 256) : buf[clone_from];
+
+        /* Head */
+
+        memcpy(tmp_buf, buf, clone_to);
+
+        /* Inserted part */
+
+        memset(tmp_buf + clone_to, item, clone_len);
+
+        /* Tail */
+        memcpy(tmp_buf + clone_to + clone_len, buf + clone_to, len - clone_to);
+
+        len += clone_len;
+        memcpy(buf, tmp_buf, len);
+
+        break;
+
+      }
+
+      case MUT_ASCIINUM: {
+
+        if (unlikely(len < 4)) { break; }  // no retry
+
+        u32 off = rand_below(afl, len), off2 = off, cnt = 0;
+
+        while (off2 + cnt < len && !isdigit(buf[off2 + cnt])) {
+
+          ++cnt;
+
+        }
+
+        // none found, wrap
+        if (off2 + cnt == len) {
+
+          off2 = 0;
+          cnt = 0;
+
+          while (cnt < off && !isdigit(buf[off2 + cnt])) {
+
+            ++cnt;
+
+          }
+
+          if (cnt == off) {
+
+            if (len < 8) {
+
+              break;
+
+            } else {
+
+              goto retry_havoc_step;
+
+            }
+
+          }
+
+        }
+
+        off = off2 + cnt;
+        off2 = off + 1;
+
+        while (off2 < len && isdigit(buf[off2])) {
+
+          ++off2;
+
+        }
+
+        s64 val = buf[off] - '0';
+        for (u32 i = off + 1; i < off2; ++i) {
+
+          val = (val * 10) + buf[i] - '0';
+
+        }
+
+        if (off && buf[off - 1] == '-') { val = -val; }
+
+        u32 strat = rand_below(afl, 8);
+        switch (strat) {
+
+          case 0:
+            val++;
+            break;
+          case 1:
+            val--;
+            break;
+          case 2:
+            val *= 2;
+            break;
+          case 3:
+            val /= 2;
+            break;
+          case 4:
+            if (likely(val && (u64)val < 0x19999999)) {
+
+              val = (u64)rand_next(afl) % (u64)((u64)val * 10);
+
+            } else {
+
+              val = rand_below(afl, 256);
+
+            }
+
+            break;
+          case 5:
+            val += rand_below(afl, 256);
+            break;
+          case 6:
+            val -= rand_below(afl, 256);
+            break;
+          case 7:
+            val = ~(val);
+            break;
+
+        }
+
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%ld", val);
+        u32 old_len = off2 - off;
+        u32 new_len = strlen(buf);
+
+        if (old_len == new_len) {
+
+          memcpy(buf + off, buf, new_len);
+
+        } else {
+
+          /* Head */
+
+          memcpy(tmp_buf, buf, off);
+
+          /* Inserted part */
+
+          memcpy(tmp_buf + off, buf, new_len);
+
+          /* Tail */
+          memcpy(tmp_buf + off + new_len, buf + off2, len - off2);
+
+          len += (new_len - old_len);
+          memcpy(buf, tmp_buf, len);
+
+        }
+
+        // fprintf(stderr, "AFTER : %s\n", buf);
+        break;
+
+      }
+
+      case MUT_NEG: {
+
+        /* Neg byte. */
+
+        item = rand_below(afl, len);
+        buf[item] = ~buf[item];
+
+        break;
+
+      }
+
+      case MUT_INSERTASCIINUM: {
+
+        u32 len = 1 + rand_below(afl, 8);
+        u32 pos = rand_below(afl, len);
+
+        /* Insert ascii number. */
+        if (unlikely(len < pos + len)) {
+
+          if (unlikely(len < 8)) {
+
+            break;
+
+          } else {
+
+            goto retry_havoc_step;
+
+          }
+
+        }
+
+        u64  val = rand_next(afl);
+        char buf[20];
+        snprintf(buf, sizeof(buf), "%llu", val);
+        memcpy(buf + pos, buf, len);
+
+        break;
+
+      }
+
+      case MUT_EXTRA_OVERWRITE: {
+
+        if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
+
+        /* Use the dictionary. */
+
+        u32 use_extra = rand_below(afl, afl->extras_cnt);
+        u32 extra_len = afl->extras[use_extra].len;
+
+        if (unlikely(extra_len > len)) { goto retry_havoc_step; }
+
+        u32 insert_at = rand_below(afl, len - extra_len + 1);
+        memcpy(buf + insert_at, afl->extras[use_extra].data, extra_len);
+
+        break;
+
+      }
+
+      case MUT_EXTRA_INSERT: {
+
+        if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
+
+        u32 use_extra = rand_below(afl, afl->extras_cnt);
+        u32 extra_len = afl->extras[use_extra].len;
+        if (unlikely(len + extra_len >= MAX_FILE)) { goto retry_havoc_step; }
+
+        u8 *ptr = afl->extras[use_extra].data;
+        u32 insert_at = rand_below(afl, len + 1);
+
+        /* Tail */
+        memmove(buf + insert_at + extra_len, buf + insert_at, len - insert_at);
+
+        /* Inserted part */
+        memcpy(buf + insert_at, ptr, extra_len);
+        len += extra_len;
+
+        break;
+
+      }
+
+      case MUT_AUTO_EXTRA_OVERWRITE: {
+
+        if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
+
+        /* Use the dictionary. */
+
+        u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+        u32 extra_len = afl->a_extras[use_extra].len;
+
+        if (unlikely(extra_len > len)) { goto retry_havoc_step; }
+
+        u32 insert_at = rand_below(afl, len - extra_len + 1);
+        memcpy(buf + insert_at, afl->a_extras[use_extra].data, extra_len);
+
+        break;
+
+      }
+
+      case MUT_AUTO_EXTRA_INSERT: {
+
+        if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
+
+        u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+        u32 extra_len = afl->a_extras[use_extra].len;
+        if (unlikely(len + extra_len >= MAX_FILE)) { goto retry_havoc_step; }
+
+        u8 *ptr = afl->a_extras[use_extra].data;
+        u32 insert_at = rand_below(afl, len + 1);
+
+        /* Tail */
+        memmove(buf + insert_at + extra_len, buf + insert_at, len - insert_at);
+
+        /* Inserted part */
+        memcpy(buf + insert_at, ptr, extra_len);
+        len += extra_len;
+
+        break;
+
+      }
+
+      case MUT_SPLICE_OVERWRITE: {
+
+        if (unlikely(!splice_buf || !splice_len)) { goto retry_havoc_step; }
+
+        /* overwrite mode */
+
+        u32 copy_from, copy_to, copy_len;
+
+        copy_len = choose_block_len(afl, splice_len - 1);
+
+        if (copy_len > len) copy_len = len;
+
+        copy_from = rand_below(afl, splice_len - copy_len + 1);
+        copy_to = rand_below(afl, len - copy_len + 1);
+        memmove(buf + copy_to, splice_buf + copy_from, copy_len);
+
+        break;
+
+      }
+
+      case MUT_SPLICE_INSERT: {
+
+        if (unlikely(!splice_buf || !splice_len)) { goto retry_havoc_step; }
+
+        if (unlikely(len + HAVOC_BLK_XL >= MAX_FILE)) { goto retry_havoc_step; }
+
+        /* insert mode */
+
+        u32 clone_from, clone_to, clone_len;
+
+        clone_len = choose_block_len(afl, splice_len);
+        clone_from = rand_below(afl, splice_len - clone_len + 1);
+        clone_to = rand_below(afl, len + 1);
+
+        /* Head */
+
+        memcpy(tmp_buf, buf, clone_to);
+
+        /* Inserted part */
+
+        memcpy(tmp_buf + clone_to, splice_buf + clone_from, clone_len);
+
+        /* Tail */
+        memcpy(tmp_buf + clone_to + clone_len, buf + clone_to, len - clone_to);
+
+        len += clone_len;
+        memcpy(buf, tmp_buf, len);
+
+        break;
+
+      }
+
+    }
+
+  }
+
+  return len;
+
+}
+
+#endif                                                  /* !AFL_MUTATIONS_H */
+
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 1636c323..226fb40e 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -27,21 +27,7 @@
 #include <string.h>
 #include <limits.h>
 #include "cmplog.h"
-
-static u32 mutation_array_explore[] = {
-
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18,
-    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
-// static u32 mutation_array_exploit[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
-// 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-// 31 }; static u32 mutation_array_txt_explore[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
-// 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
-// 28, 29, 30, 31 }; static u32 mutation_array_txt_exploit[] = { 0, 1, 2, 3, 4,
-// 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
-// 25, 26, 27, 28, 29, 30, 31 };
-
-// what about more splicing?
-// what about -x and cmplog learn?
+#include "afl-mutations.h"
 
 /* MOpt */
 
@@ -85,50 +71,6 @@ static int select_algorithm(afl_state_t *afl, u32 max_algorithm) {
 
 }
 
-/* Helper to choose random block len for block operations in fuzz_one().
-   Doesn't return zero, provided that max_len is > 0. */
-
-static inline u32 choose_block_len(afl_state_t *afl, u32 limit) {
-
-  u32 min_value, max_value;
-  u32 rlim = MIN(afl->queue_cycle, (u32)3);
-
-  if (unlikely(!afl->run_over10m)) { rlim = 1; }
-
-  switch (rand_below(afl, rlim)) {
-
-    case 0:
-      min_value = 1;
-      max_value = HAVOC_BLK_SMALL;
-      break;
-
-    case 1:
-      min_value = HAVOC_BLK_SMALL;
-      max_value = HAVOC_BLK_MEDIUM;
-      break;
-
-    default:
-
-      if (likely(rand_below(afl, 10))) {
-
-        min_value = HAVOC_BLK_MEDIUM;
-        max_value = HAVOC_BLK_LARGE;
-
-      } else {
-
-        min_value = HAVOC_BLK_LARGE;
-        max_value = HAVOC_BLK_XL;
-
-      }
-
-  }
-
-  if (min_value >= limit) { min_value = 1; }
-
-  return min_value + rand_below(afl, MIN(max_value, limit) - min_value + 1);
-
-}
-
 /* Helper function to see if a particular change (xor_val = old ^ new) could
    be a product of deterministic bit flips with the lengths and stepovers
    attempted by afl-fuzz. This is used to avoid dupes in some of the
@@ -2136,8 +2078,31 @@ havoc_stage:
   u32 *mutation_array;
   u32  stack_max;
 
-  // if ( ... )
-  mutation_array = (u32 *)&mutation_array_explore;
+  if (afl->queue_cur->is_ascii) {  // is text?
+
+    if (1) {  // is exploration?
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploration_text;
+
+    } else {  // is exploitation!
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploitation_text;
+
+    }
+
+  } else {  // is binary!
+
+    if (1) {  // is exploration?
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploration_binary;
+
+    } else {  // is exploitation!
+
+      mutation_array = (unsigned int *)&mutation_strategy_exploitation_binary;
+
+    }
+
+  }
 
   if (temp_len < 64) {
 
@@ -2208,11 +2173,11 @@ havoc_stage:
       }
 
     retry_havoc_step:
-      u32 r = rand_below(afl, 256), item;
+      u32 r = rand_below(afl, MUT_STRATEGY_ARRAY_SIZE), item;
 
       switch (mutation_array[r]) {
 
-        case 0: {
+        case MUT_FLIPBIT: {
 
           /* Flip a single bit somewhere. Spooky! */
           u8  bit = rand_below(afl, 8);
@@ -2227,7 +2192,7 @@ havoc_stage:
 
         }
 
-        case 1: {
+        case MUT_INTERESTING8: {
 
           /* Set byte to interesting value. */
 
@@ -2241,7 +2206,7 @@ havoc_stage:
 
         }
 
-        case 2: {
+        case MUT_INTERESTING16: {
 
           /* Set word to interesting value, little endian. */
 
@@ -2260,7 +2225,7 @@ havoc_stage:
 
         }
 
-        case 3: {
+        case MUT_INTERESTING16BE: {
 
           /* Set word to interesting value, big endian. */
 
@@ -2278,7 +2243,7 @@ havoc_stage:
 
         }
 
-        case 4: {
+        case MUT_INTERESTING32: {
 
           /* Set dword to interesting value, little endian. */
 
@@ -2297,7 +2262,7 @@ havoc_stage:
 
         }
 
-        case 5: {
+        case MUT_INTERESTING32BE: {
 
           /* Set dword to interesting value, big endian. */
 
@@ -2315,7 +2280,7 @@ havoc_stage:
 
         }
 
-        case 6: {
+        case MUT_ARITH8_: {
 
           /* Randomly subtract from byte. */
 
@@ -2329,7 +2294,7 @@ havoc_stage:
 
         }
 
-        case 7: {
+        case MUT_ARITH8: {
 
           /* Randomly add to byte. */
 
@@ -2343,7 +2308,7 @@ havoc_stage:
 
         }
 
-        case 8: {
+        case MUT_ARITH16_: {
 
           /* Randomly subtract from word, little endian. */
 
@@ -2362,7 +2327,7 @@ havoc_stage:
 
         }
 
-        case 9: {
+        case MUT_ARITH16BE_: {
 
           /* Randomly subtract from word, big endian. */
 
@@ -2382,7 +2347,7 @@ havoc_stage:
 
         }
 
-        case 10: {
+        case MUT_ARITH16: {
 
           /* Randomly add to word, little endian. */
 
@@ -2401,7 +2366,7 @@ havoc_stage:
 
         }
 
-        case 11: {
+        case MUT_ARITH16BE: {
 
           /* Randomly add to word, big endian. */
 
@@ -2421,7 +2386,7 @@ havoc_stage:
 
         }
 
-        case 12: {
+        case MUT_ARITH32_: {
 
           /* Randomly subtract from dword, little endian. */
 
@@ -2440,7 +2405,7 @@ havoc_stage:
 
         }
 
-        case 13: {
+        case MUT_ARITH32BE_: {
 
           /* Randomly subtract from dword, big endian. */
 
@@ -2460,7 +2425,7 @@ havoc_stage:
 
         }
 
-        case 14: {
+        case MUT_ARITH32: {
 
           /* Randomly add to dword, little endian. */
 
@@ -2479,7 +2444,7 @@ havoc_stage:
 
         }
 
-        case 15: {
+        case MUT_ARITH32BE: {
 
           /* Randomly add to dword, big endian. */
 
@@ -2499,7 +2464,7 @@ havoc_stage:
 
         }
 
-        case 16: {
+        case MUT_RAND8: {
 
           /* Just set a random byte to a random value. Because,
              why not. We use XOR with 1-255 to eliminate the
@@ -2517,7 +2482,7 @@ havoc_stage:
 
         }
 
-        case 17: {
+        case MUT_CLONE_OVERWRITE: {
 
           if (likely(temp_len + HAVOC_BLK_XL < MAX_FILE)) {
 
@@ -2566,7 +2531,7 @@ havoc_stage:
 
         }
 
-        case 18: {
+        case MUT_CLONE_INSERT: {
 
           if (likely(temp_len + HAVOC_BLK_XL < MAX_FILE)) {
 
@@ -2617,7 +2582,7 @@ havoc_stage:
 
         }
 
-        case 19: {
+        case MUT_OVERWRITE_COPY: {
 
           /* Overwrite bytes with a randomly selected chunk bytes. */
 
@@ -2642,7 +2607,7 @@ havoc_stage:
 
         }
 
-        case 20: {
+        case MUT_OVERWRITE_FIXED: {
 
           /* Overwrite bytes with fixed bytes. */
 
@@ -2666,7 +2631,7 @@ havoc_stage:
 
         }
 
-        case 21: {
+        case MUT_BYTEADD: {
 
           /* Increase byte by 1. */
 
@@ -2679,7 +2644,7 @@ havoc_stage:
 
         }
 
-        case 22: {
+        case MUT_BYTESUB: {
 
           /* Decrease byte by 1. */
 
@@ -2692,7 +2657,7 @@ havoc_stage:
 
         }
 
-        case 23: {
+        case MUT_FLIP8: {
 
           /* Flip byte. */
 
@@ -2705,7 +2670,7 @@ havoc_stage:
 
         }
 
-        case 24: {
+        case MUT_SWITCH: {
 
           if (unlikely(temp_len < 4)) { break; }  // no retry
 
@@ -2757,7 +2722,7 @@ havoc_stage:
 
         }
 
-        case 25: {
+        case MUT_DEL: {
 
           /* Delete bytes. */
 
@@ -2782,7 +2747,7 @@ havoc_stage:
 
         }
 
-        case 26: {
+        case MUT_SHUFFLE: {
 
           /* Shuffle bytes. */
 
@@ -2815,7 +2780,7 @@ havoc_stage:
 
         }
 
-        case 27: {
+        case MUT_DELONE: {
 
           /* Delete bytes. */
 
@@ -2839,7 +2804,7 @@ havoc_stage:
 
         }
 
-        case 28: {
+        case MUT_INSERTONE: {
 
           if (unlikely(temp_len < 2)) { break; }  // no retry
 
@@ -2878,7 +2843,7 @@ havoc_stage:
 
         }
 
-        case 29: {
+        case MUT_ASCIINUM: {
 
           if (unlikely(temp_len < 4)) { break; }  // no retry
 
@@ -3022,7 +2987,7 @@ havoc_stage:
 
         }
 
-        case 30: {
+        case MUT_NEG: {
 
           /* Neg byte. */
 
@@ -3037,7 +3002,7 @@ havoc_stage:
 
         }
 
-        case 31: {
+        case MUT_INSERTASCIINUM: {
 
           u32 len = 1 + rand_below(afl, 8);
           u32 pos = rand_below(afl, temp_len);
@@ -3069,7 +3034,7 @@ havoc_stage:
 
         }
 
-        case 32: {
+        case MUT_EXTRA_OVERWRITE: {
 
           if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
 
@@ -3092,7 +3057,7 @@ havoc_stage:
 
         }
 
-        case 33: {
+        case MUT_EXTRA_INSERT: {
 
           if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
 
@@ -3127,7 +3092,7 @@ havoc_stage:
 
         }
 
-        case 34: {
+        case MUT_AUTO_EXTRA_OVERWRITE: {
 
           if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
 
@@ -3150,7 +3115,7 @@ havoc_stage:
 
         }
 
-        case 35: {
+        case MUT_AUTO_EXTRA_INSERT: {
 
           if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
 
@@ -3185,7 +3150,7 @@ havoc_stage:
 
         }
 
-        case 36: {
+        case MUT_SPLICE_OVERWRITE: {
 
           if (unlikely(afl->ready_for_splicing_count <= 1)) {
 
@@ -3231,7 +3196,7 @@ havoc_stage:
 
         }
 
-        case 37: {
+        case MUT_SPLICE_INSERT: {
 
           if (unlikely(afl->ready_for_splicing_count <= 1)) {