about summary refs log tree commit diff
path: root/examples/custom_mutators/example.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/custom_mutators/example.c')
-rw-r--r--examples/custom_mutators/example.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c
new file mode 100644
index 00000000..63e4d6da
--- /dev/null
+++ b/examples/custom_mutators/example.c
@@ -0,0 +1,177 @@
+/*
+  New Custom Mutator for AFL++
+  Written by Khaled Yakdan <yakdan@code-intelligence.de>
+             Andrea Fioraldi <andreafioraldi@gmail.com>
+             Shengtuo Hu <h1994st@gmail.com>
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char *commands[] = {
+
+    "GET",
+    "PUT",
+    "DEL",
+
+};
+
+static size_t data_size = 100;
+
+void afl_custom_init(unsigned int seed) {
+
+  srand(seed);
+
+}
+
+/**
+ * Perform custom mutations on a given input
+ *
+ * (Optional for now. Required in the future)
+ *
+ * @param[in] buf Input data to be mutated
+ * @param[in] buf_size Size of input data
+ * @param[in] add_buf Buffer containing the additional test case
+ * @param[in] add_buf_size Size of the additional test case
+ * @param[out] mutated_out Buffer to store the mutated input
+ * @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(uint8_t *buf, size_t buf_size,
+                       uint8_t *add_buf,size_t add_buf_size, // add_buf can be NULL
+                       uint8_t *mutated_out, 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;
+
+  // 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
+  for (int i = 3; i < mutated_size; i++) {
+
+    mutated_out[i] = (data[i] + rand() % 10) & 0xff;
+
+  }
+
+  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] 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. AFL++
+ *     will release the memory after saving the test case.
+ * @return Size of the output buffer after processing
+ */
+size_t afl_custom_pre_save(uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
+
+  size_t out_buf_size;
+
+  out_buf_size = buf_size;
+
+  // External mutator should allocate memory for `out_buf`
+  *out_buf = malloc(out_buf_size);
+  memcpy(*out_buf, buf, out_buf_size);
+
+  return out_buf_size;
+
+}
+
+uint8_t *trim_buf;
+size_t trim_buf_size
+int trimmming_steps;
+int cur_step;
+
+/**
+ * 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 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
+ */
+int afl_custom_init_trim(uint8_t *buf, size_t buf_size) {
+
+  // We simply trim once
+  trimmming_steps = 1;
+
+  cur_step = 0;
+  trim_buf = buf;
+  trim_buf_size = buf_size;
+
+  return 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 global variables. 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[out] out_buf Pointer to the buffer containing the trimmed test case.
+ *     External library should allocate memory for out_buf. AFL++ will release
+ *     the memory after saving the test case.
+ * @param[out] out_buf_size Pointer to the size of the trimmed test case
+ */
+void afl_custom_trim(uint8_t **out_buf, size_t* out_buf_size) {
+
+  *out_buf_size = trim_buf_size - 1;
+
+  // External mutator should allocate memory for `out_buf`
+  *out_buf = malloc(*out_buf_size);
+  // Remove the last byte of the trimming input
+  memcpy(*out_buf, trim_buf, *out_buf_size);
+
+}
+
+/**
+ * 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 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)
+ */
+int afl_custom_post_trim(int success) {
+
+  if (success) {
+    ++cur_step;
+    return cur_step;
+  }
+
+  return trimmming_steps;
+
+}