about summary refs log tree commit diff
path: root/utils/custom_mutators/example.c
diff options
context:
space:
mode:
authorvanhauser-thc <vh@thc.org>2020-12-01 14:40:30 +0100
committervanhauser-thc <vh@thc.org>2020-12-01 14:40:30 +0100
commitc05e4efbe9b4e7d1ff078b7a392621f2ca7572e6 (patch)
treee005593b09169435cbad53c9990c6485e8fd9d06 /utils/custom_mutators/example.c
parent8584f9d2b5de9687c518c672e471f4f8cd9166fa (diff)
downloadafl++-c05e4efbe9b4e7d1ff078b7a392621f2ca7572e6.tar.gz
renamed examples/ to utils/
Diffstat (limited to 'utils/custom_mutators/example.c')
-rw-r--r--utils/custom_mutators/example.c376
1 files changed, 376 insertions, 0 deletions
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);
+
+}
+