aboutsummaryrefslogtreecommitdiff
path: root/examples/custom_mutators
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 /examples/custom_mutators
parent8584f9d2b5de9687c518c672e471f4f8cd9166fa (diff)
downloadafl++-c05e4efbe9b4e7d1ff078b7a392621f2ca7572e6.tar.gz
renamed examples/ to utils/
Diffstat (limited to 'examples/custom_mutators')
-rw-r--r--examples/custom_mutators/Makefile7
-rw-r--r--examples/custom_mutators/README.md35
-rw-r--r--examples/custom_mutators/XmlMutatorMin.py332
-rw-r--r--examples/custom_mutators/common.py40
-rw-r--r--examples/custom_mutators/custom_mutator_helpers.h342
-rw-r--r--examples/custom_mutators/example.c376
-rw-r--r--examples/custom_mutators/example.py186
-rw-r--r--examples/custom_mutators/post_library_gif.so.c165
-rw-r--r--examples/custom_mutators/post_library_png.so.c163
-rw-r--r--examples/custom_mutators/simple-chunk-replace.py64
-rw-r--r--examples/custom_mutators/simple_example.c74
-rw-r--r--examples/custom_mutators/wrapper_afl_min.py118
12 files changed, 0 insertions, 1902 deletions
diff --git a/examples/custom_mutators/Makefile b/examples/custom_mutators/Makefile
deleted file mode 100644
index 9849f3f4..00000000
--- a/examples/custom_mutators/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-all: libexamplemutator.so
-
-libexamplemutator.so:
- $(CC) $(CFLAGS) -D_FORTIFY_SOURCE=2 -O3 -fPIC -shared -g -I ../../include example.c -o libexamplemutator.so
-
-clean:
- rm -rf libexamplemutator.so
diff --git a/examples/custom_mutators/README.md b/examples/custom_mutators/README.md
deleted file mode 100644
index 655f7a5e..00000000
--- a/examples/custom_mutators/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Examples for the custom mutator
-
-These are example and helper files for the custom mutator feature.
-See [docs/custom_mutators.md](../../docs/custom_mutators.md) for more information
-
-Note that if you compile with python3.7 you must use python3 scripts, and if
-you use python2.7 to compile python2 scripts!
-
-simple_example.c - most simplest example. generates a random sized buffer
- filled with 'A'
-
-example.c - this is a simple example written in C and should be compiled to a
- shared library. Use make to compile it and produce libexamplemutator.so
-
-example.py - this is the template you can use, the functions are there but they
- are empty
-
-post_library_gif.so.c - fix a fuzz input to ensure it is valid for GIF
-
-post_library_png.so.c - fix a fuzz input to ensure it is valid for PNG
-
-simple-chunk-replace.py - this is a simple example where chunks are replaced
-
-common.py - this can be used for common functions and helpers.
- the examples do not use this though. But you can :)
-
-wrapper_afl_min.py - mutation of XML documents, loads XmlMutatorMin.py
-
-XmlMutatorMin.py - module for XML mutation
-
-custom_mutator_helpers.h is an header that defines some helper routines
-like surgical_havoc_mutate() that allow to perform a randomly chosen
-mutation from a subset of the havoc mutations.
-If you do so, you have to specify -I /path/to/AFLplusplus/include when
-compiling.
diff --git a/examples/custom_mutators/XmlMutatorMin.py b/examples/custom_mutators/XmlMutatorMin.py
deleted file mode 100644
index 4c80a2ba..00000000
--- a/examples/custom_mutators/XmlMutatorMin.py
+++ /dev/null
@@ -1,332 +0,0 @@
-#!/usr/bin/python
-
-""" Mutation of XML documents, should be called from one of its wrappers (CLI, AFL, ...) """
-
-from __future__ import print_function
-from copy import deepcopy
-from lxml import etree as ET
-import random, re, io
-
-
-###########################
-# The XmlMutatorMin class #
-###########################
-
-class XmlMutatorMin:
-
- """
- Optionals parameters:
- seed Seed used by the PRNG (default: "RANDOM")
- verbose Verbosity (default: False)
- """
-
- def __init__(self, seed="RANDOM", verbose=False):
-
- """ Initialize seed, database and mutators """
-
- # Verbosity
- self.verbose = verbose
-
- # Initialize PRNG
- self.seed = str(seed)
- if self.seed == "RANDOM":
- random.seed()
- else:
- if self.verbose:
- print("Static seed '%s'" % self.seed)
- random.seed(self.seed)
-
- # Initialize input and output documents
- self.input_tree = None
- self.tree = None
-
- # High-level mutators (no database needed)
- hl_mutators_delete = ["del_node_and_children", "del_node_but_children", "del_attribute", "del_content"] # Delete items
- hl_mutators_fuzz = ["fuzz_attribute"] # Randomly change attribute values
-
- # Exposed mutators
- self.hl_mutators_all = hl_mutators_fuzz + hl_mutators_delete
-
- def __parse_xml(self, xml):
-
- """ Parse an XML string. Basic wrapper around lxml.parse() """
-
- try:
- # Function parse() takes care of comments / DTD / processing instructions / ...
- tree = ET.parse(io.BytesIO(xml))
- except ET.ParseError:
- raise RuntimeError("XML isn't well-formed!")
- except LookupError as e:
- raise RuntimeError(e)
-
- # Return a document wrapper
- return tree
-
- def __exec_among(self, module, functions, min_times, max_times):
-
- """ Randomly execute $functions between $min and $max times """
-
- for i in xrange(random.randint(min_times, max_times)):
- # Function names are mangled because they are "private"
- getattr(module, "_XmlMutatorMin__" + random.choice(functions))()
-
- def __serialize_xml(self, tree):
-
- """ Serialize a XML document. Basic wrapper around lxml.tostring() """
-
- return ET.tostring(tree, with_tail=False, xml_declaration=True, encoding=tree.docinfo.encoding)
-
- def __ver(self, version):
-
- """ Helper for displaying lxml version numbers """
-
- return ".".join(map(str, version))
-
- def reset(self):
-
- """ Reset the mutator """
-
- self.tree = deepcopy(self.input_tree)
-
- def init_from_string(self, input_string):
-
- """ Initialize the mutator from a XML string """
-
- # Get a pointer to the top-element
- self.input_tree = self.__parse_xml(input_string)
-
- # Get a working copy
- self.tree = deepcopy(self.input_tree)
-
- def save_to_string(self):
-
- """ Return the current XML document as UTF-8 string """
-
- # Return a text version of the tree
- return self.__serialize_xml(self.tree)
-
- def __pick_element(self, exclude_root_node=False):
-
- """ Pick a random element from the current document """
-
- # Get a list of all elements, but nodes like PI and comments
- elems = list(self.tree.getroot().iter(tag=ET.Element))
-
- # Is the root node excluded?
- if exclude_root_node:
- start = 1
- else:
- start = 0
-
- # Pick a random element
- try:
- elem_id = random.randint(start, len(elems) - 1)
- elem = elems[elem_id]
- except ValueError:
- # Should only occurs if "exclude_root_node = True"
- return (None, None)
-
- return (elem_id, elem)
-
- def __fuzz_attribute(self):
-
- """ Fuzz (part of) an attribute value """
-
- # Select a node to modify
- (rand_elem_id, rand_elem) = self.__pick_element()
-
- # Get all the attributes
- attribs = rand_elem.keys()
-
- # Is there attributes?
- if len(attribs) < 1:
- if self.verbose:
- print("No attribute: can't replace!")
- return
-
- # Pick a random attribute
- rand_attrib_id = random.randint(0, len(attribs) - 1)
- rand_attrib = attribs[rand_attrib_id]
-
- # We have the attribute to modify
- # Get its value
- attrib_value = rand_elem.get(rand_attrib)
- # print("- Value: " + attrib_value)
-
- # Should we work on the whole value?
- func_call = "(?P<func>[a-zA-Z:\-]+)\((?P<args>.*?)\)"
- p = re.compile(func_call)
- l = p.findall(attrib_value)
- if random.choice((True, False)) and l:
- # Randomly pick one the function calls
- (func, args) = random.choice(l)
- # Split by "," and randomly pick one of the arguments
- value = random.choice(args.split(','))
- # Remove superfluous characters
- unclean_value = value
- value = value.strip(" ").strip("'")
- # print("Selected argument: [%s]" % value)
- else:
- value = attrib_value
-
- # For each type, define some possible replacement values
- choices_number = ( \
- "0", \
- "11111", \
- "-128", \
- "2", \
- "-1", \
- "1/3", \
- "42/0", \
- "1094861636 idiv 1.0", \
- "-1123329771506872 idiv 3.8", \
- "17=$numericRTF", \
- str(3 + random.randrange(0, 100)), \
- )
-
- choices_letter = ( \
- "P" * (25 * random.randrange(1, 100)), \
- "%s%s%s%s%s%s", \
- "foobar", \
- )
-
- choices_alnum = ( \
- "Abc123", \
- "020F0302020204030204", \
- "020F0302020204030204" * (random.randrange(5, 20)), \
- )
-
- # Fuzz the value
- if random.choice((True,False)) and value == "":
-
- # Empty
- new_value = value
-
- elif random.choice((True,False)) and value.isdigit():
-
- # Numbers
- new_value = random.choice(choices_number)
-
- elif random.choice((True,False)) and value.isalpha():
-
- # Letters
- new_value = random.choice(choices_letter)
-
- elif random.choice((True,False)) and value.isalnum():
-
- # Alphanumeric
- new_value = random.choice(choices_alnum)
-
- else:
-
- # Default type
- new_value = random.choice(choices_alnum + choices_letter + choices_number)
-
- # If we worked on a substring, apply changes to the whole string
- if value != attrib_value:
- # No ' around empty values
- if new_value != "" and value != "":
- new_value = "'" + new_value + "'"
- # Apply changes
- new_value = attrib_value.replace(unclean_value, new_value)
-
- # Log something
- if self.verbose:
- print("Fuzzing attribute #%i '%s' of tag #%i '%s'" % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag))
-
- # Modify the attribute
- rand_elem.set(rand_attrib, new_value.decode("utf-8"))
-
- def __del_node_and_children(self):
-
- """ High-level minimizing mutator
- Delete a random node and its children (i.e. delete a random tree) """
-
- self.__del_node(True)
-
- def __del_node_but_children(self):
-
- """ High-level minimizing mutator
- Delete a random node but its children (i.e. link them to the parent of the deleted node) """
-
- self.__del_node(False)
-
- def __del_node(self, delete_children):
-
- """ Called by the __del_node_* mutators """
-
- # Select a node to modify (but the root one)
- (rand_elem_id, rand_elem) = self.__pick_element(exclude_root_node=True)
-
- # If the document includes only a top-level element
- # Then we can't pick a element (given that "exclude_root_node = True")
-
- # Is the document deep enough?
- if rand_elem is None:
- if self.verbose:
- print("Can't delete a node: document not deep enough!")
- return
-
- # Log something
- if self.verbose:
- but_or_and = "and" if delete_children else "but"
- print("Deleting tag #%i '%s' %s its children" % (rand_elem_id, rand_elem.tag, but_or_and))
-
- if delete_children is False:
- # Link children of the random (soon to be deleted) node to its parent
- for child in rand_elem:
- rand_elem.getparent().append(child)
-
- # Remove the node
- rand_elem.getparent().remove(rand_elem)
-
- def __del_content(self):
-
- """ High-level minimizing mutator
- Delete the attributes and children of a random node """
-
- # Select a node to modify
- (rand_elem_id, rand_elem) = self.__pick_element()
-
- # Log something
- if self.verbose:
- print("Reseting tag #%i '%s'" % (rand_elem_id, rand_elem.tag))
-
- # Reset the node
- rand_elem.clear()
-
- def __del_attribute(self):
-
- """ High-level minimizing mutator
- Delete a random attribute from a random node """
-
- # Select a node to modify
- (rand_elem_id, rand_elem) = self.__pick_element()
-
- # Get all the attributes
- attribs = rand_elem.keys()
-
- # Is there attributes?
- if len(attribs) < 1:
- if self.verbose:
- print("No attribute: can't delete!")
- return
-
- # Pick a random attribute
- rand_attrib_id = random.randint(0, len(attribs) - 1)
- rand_attrib = attribs[rand_attrib_id]
-
- # Log something
- if self.verbose:
- print("Deleting attribute #%i '%s' of tag #%i '%s'" % (rand_attrib_id, rand_attrib, rand_elem_id, rand_elem.tag))
-
- # Delete the attribute
- rand_elem.attrib.pop(rand_attrib)
-
- def mutate(self, min=1, max=5):
-
- """ Execute some high-level mutators between $min and $max times, then some medium-level ones """
-
- # High-level mutation
- self.__exec_among(self, self.hl_mutators_all, min, max)
-
diff --git a/examples/custom_mutators/common.py b/examples/custom_mutators/common.py
deleted file mode 100644
index 9a1ef0a3..00000000
--- a/examples/custom_mutators/common.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-'''
-Module containing functions shared between multiple AFL modules
-
-@author: Christian Holler (:decoder)
-
-@license:
-
-This Source Code Form is subject to the terms of the Mozilla Public
-License, v. 2.0. If a copy of the MPL was not distributed with this
-file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-@contact: choller@mozilla.com
-'''
-
-from __future__ import print_function
-import random
-import os
-import re
-
-
-def randel(l):
- if not l:
- return None
- return l[random.randint(0, len(l)-1)]
-
-
-def randel_pop(l):
- if not l:
- return None
- return l.pop(random.randint(0, len(l)-1))
-
-
-def write_exc_example(data, exc):
- exc_name = re.sub(r'[^a-zA-Z0-9]', '_', repr(exc))
-
- if not os.path.exists(exc_name):
- with open(exc_name, 'w') as f:
- f.write(data)
diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h
deleted file mode 100644
index 62e6efba..00000000
--- a/examples/custom_mutators/custom_mutator_helpers.h
+++ /dev/null
@@ -1,342 +0,0 @@
-#ifndef CUSTOM_MUTATOR_HELPERS
-#define CUSTOM_MUTATOR_HELPERS
-
-#include "config.h"
-#include "types.h"
-#include <stdlib.h>
-
-#define INITIAL_GROWTH_SIZE (64)
-
-#define RAND_BELOW(limit) (rand() % (limit))
-
-/* Use in a struct: creates a name_buf and a name_size variable. */
-#define BUF_VAR(type, name) \
- type * name##_buf; \
- size_t name##_size;
-/* this fills in `&structptr->something_buf, &structptr->something_size`. */
-#define BUF_PARAMS(struct, name) \
- (void **)&struct->name##_buf, &struct->name##_size
-
-typedef struct {
-
-} afl_t;
-
-static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
-
- static s8 interesting_8[] = {INTERESTING_8};
- static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
- static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
-
- switch (RAND_BELOW(12)) {
-
- case 0: {
-
- /* Flip a single bit somewhere. Spooky! */
-
- s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
-
- out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
-
- break;
-
- }
-
- case 1: {
-
- /* Set byte to interesting value. */
-
- u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
- out_buf[(RAND_BELOW(end - begin) + begin)] = val;
-
- break;
-
- }
-
- case 2: {
-
- /* Set word to interesting value, randomly choosing endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u16 *)(out_buf + byte_idx) =
- interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
- break;
- case 1:
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
- break;
-
- }
-
- break;
-
- }
-
- case 3: {
-
- /* Set dword to interesting value, randomly choosing endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u32 *)(out_buf + byte_idx) =
- interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
- break;
- case 1:
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
- break;
-
- }
-
- break;
-
- }
-
- case 4: {
-
- /* Set qword to interesting value, randomly choosing endian. */
-
- if (end - begin < 8) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 7) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u64 *)(out_buf + byte_idx) =
- (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
- break;
- case 1:
- *(u64 *)(out_buf + byte_idx) = SWAP64(
- (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
- break;
-
- }
-
- break;
-
- }
-
- case 5: {
-
- /* Randomly subtract from byte. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
-
- break;
-
- }
-
- case 6: {
-
- /* Randomly add to byte. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
-
- break;
-
- }
-
- case 7: {
-
- /* Randomly subtract from word, random endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- if (RAND_BELOW(2)) {
-
- *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
-
- }
-
- break;
-
- }
-
- case 8: {
-
- /* Randomly add to word, random endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- if (RAND_BELOW(2)) {
-
- *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
-
- }
-
- break;
-
- }
-
- case 9: {
-
- /* Randomly subtract from dword, random endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- if (RAND_BELOW(2)) {
-
- *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
-
- }
-
- break;
-
- }
-
- case 10: {
-
- /* Randomly add to dword, random endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- if (RAND_BELOW(2)) {
-
- *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
-
- }
-
- break;
-
- }
-
- case 11: {
-
- /* Just set a random byte to a random value. Because,
- why not. We use XOR with 1-255 to eliminate the
- possibility of a no-op. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
-
- break;
-
- }
-
- }
-
-}
-
-/* This function calculates the next power of 2 greater or equal its argument.
- @return The rounded up power of 2 (if no overflow) or 0 on overflow.
-*/
-static inline size_t next_pow2(size_t in) {
-
- if (in == 0 || in > (size_t)-1)
- return 0; /* avoid undefined behaviour under-/overflow */
- size_t out = in - 1;
- out |= out >> 1;
- out |= out >> 2;
- out |= out >> 4;
- out |= out >> 8;
- out |= out >> 16;
- return out + 1;
-
-}
-
-/* This function makes sure *size is > size_needed after call.
- It will realloc *buf otherwise.
- *size will grow exponentially as per:
- https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
- Will return NULL and free *buf if size_needed is <1 or realloc failed.
- @return For convenience, this function returns *buf.
- */
-static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
-
- /* No need to realloc */
- if (likely(size_needed && *size >= size_needed)) return *buf;
-
- /* No initial size was set */
- if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
-
- /* grow exponentially */
- size_t next_size = next_pow2(size_needed);
-
- /* handle overflow */
- if (!next_size) { next_size = size_needed; }
-
- /* alloc */
- *buf = realloc(*buf, next_size);
- *size = *buf ? next_size : 0;
-
- return *buf;
-
-}
-
-/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
-static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
- size_t *size2) {
-
- void * scratch_buf = *buf1;
- size_t scratch_size = *size1;
- *buf1 = *buf2;
- *size1 = *size2;
- *buf2 = scratch_buf;
- *size2 = scratch_size;
-
-}
-
-#undef INITIAL_GROWTH_SIZE
-
-#endif
-
diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c
deleted file mode 100644
index 23add128..00000000
--- a/examples/custom_mutators/example.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- New Custom Mutator for AFL++
- Written by Khaled Yakdan <yakdan@code-intelligence.de>
- Andrea Fioraldi <andreafioraldi@gmail.com>
- Shengtuo Hu <h1994st@gmail.com>
- Dominik Maier <mail@dmnk.co>
-*/
-
-// You need to use -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#define DATA_SIZE (100)
-
-static const char *commands[] = {
-
- "GET",
- "PUT",
- "DEL",
-
-};
-
-typedef struct my_mutator {
-
- afl_t *afl;
-
- // any additional data here!
- size_t trim_size_current;
- int trimmming_steps;
- int cur_step;
-
- // Reused buffers:
- BUF_VAR(u8, fuzz);
- BUF_VAR(u8, data);
- BUF_VAR(u8, havoc);
- BUF_VAR(u8, trim);
- BUF_VAR(u8, post_process);
-
-} my_mutator_t;
-
-/**
- * Initialize this custom mutator
- *
- * @param[in] afl a pointer to the internal state object. Can be ignored for
- * now.
- * @param[in] seed A seed for this mutator - the same seed should always mutate
- * in the same way.
- * @return Pointer to the data object this custom mutator instance should use.
- * There may be multiple instances of this mutator in one afl-fuzz run!
- * Return NULL on error.
- */
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
-
- srand(seed); // needed also by surgical_havoc_mutate()
-
- my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
- if (!data) {
-
- perror("afl_custom_init alloc");
- return NULL;
-
- }
-
- data->afl = afl;
-
- return data;
-
-}
-
-/**
- * Perform custom mutations on a given input
- *
- * (Optional for now. Required in the future)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param[in] buf Pointer to input data to be mutated
- * @param[in] buf_size Size of input data
- * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
- * error.
- * @param[in] add_buf Buffer containing the additional test case
- * @param[in] add_buf_size Size of the additional test case
- * @param[in] max_size Maximum size of the mutated output. The mutation must not
- * produce data larger than max_size.
- * @return Size of the mutated output.
- */
-size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
- u8 **out_buf, uint8_t *add_buf,
- size_t add_buf_size, // add_buf can be NULL
- size_t max_size) {
-
- // Make sure that the packet size does not exceed the maximum size expected by
- // the fuzzer
- size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
-
- // maybe_grow is optimized to be quick for reused buffers.
- u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
- if (!mutated_out) {
-
- *out_buf = NULL;
- perror("custom mutator allocation (maybe_grow)");
- return 0; /* afl-fuzz will very likely error out after this. */
-
- }
-
- // Randomly select a command string to add as a header to the packet
- memcpy(mutated_out, commands[rand() % 3], 3);
-
- // Mutate the payload of the packet
- int i;
- for (i = 0; i < 8; ++i) {
-
- // Randomly perform one of the (no len modification) havoc mutations
- surgical_havoc_mutate(mutated_out, 3, mutated_size);
-
- }
-
- *out_buf = mutated_out;
- return mutated_size;
-
-}
-
-/**
- * A post-processing function to use right before AFL writes the test case to
- * disk in order to execute the target.
- *
- * (Optional) If this functionality is not needed, simply don't define this
- * function.
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param[in] buf Buffer containing the test case to be executed
- * @param[in] buf_size Size of the test case
- * @param[out] out_buf Pointer to the buffer containing the test case after
- * processing. External library should allocate memory for out_buf.
- * The buf pointer may be reused (up to the given buf_size);
- * @return Size of the output buffer after processing or the needed amount.
- * A return of 0 indicates an error.
- */
-size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
- size_t buf_size, uint8_t **out_buf) {
-
- uint8_t *post_process_buf =
- maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
- if (!post_process_buf) {
-
- perror("custom mutator realloc failed.");
- *out_buf = NULL;
- return 0;
-
- }
-
- memcpy(post_process_buf + 5, buf, buf_size);
- post_process_buf[0] = 'A';
- post_process_buf[1] = 'F';
- post_process_buf[2] = 'L';
- post_process_buf[3] = '+';
- post_process_buf[4] = '+';
-
- *out_buf = post_process_buf;
-
- return buf_size + 5;
-
-}
-
-/**
- * This method is called at the start of each trimming operation and receives
- * the initial buffer. It should return the amount of iteration steps possible
- * on this input (e.g. if your input has n elements and you want to remove
- * them one by one, return n, if you do a binary search, return log(n),
- * and so on...).
- *
- * If your trimming algorithm doesn't allow you to determine the amount of
- * (remaining) steps easily (esp. while running), then you can alternatively
- * return 1 here and always return 0 in post_trim until you are finished and
- * no steps remain. In that case, returning 1 in post_trim will end the
- * trimming routine. The whole current index/max iterations stuff is only used
- * to show progress.
- *
- * (Optional)
- *
- * @param data pointer returned in afl_custom_init for this fuzz case
- * @param buf Buffer containing the test case
- * @param buf_size Size of the test case
- * @return The amount of possible iteration steps to trim the input.
- * negative on error.
- */
-int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
- size_t buf_size) {
-
- // We simply trim once
- data->trimmming_steps = 1;
-
- data->cur_step = 0;
-
- if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
-
- perror("init_trim grow");
- return -1;
-
- }
-
- memcpy(data->trim_buf, buf, buf_size);
-
- data->trim_size_current = buf_size;
-
- return data->trimmming_steps;
-
-}
-
-/**
- * This method is called for each trimming operation. It doesn't have any
- * arguments because we already have the initial buffer from init_trim and we
- * can memorize the current state in *data. This can also save
- * reparsing steps for each iteration. It should return the trimmed input
- * buffer, where the returned data must not exceed the initial input data in
- * length. Returning anything that is larger than the original data (passed
- * to init_trim) will result in a fatal abort of AFLFuzz.
- *
- * (Optional)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
- * External library should allocate memory for out_buf.
- * AFL++ will not release the memory after saving the test case.
- * Keep a ref in *data.
- * *out_buf = NULL is treated as error.
- * @return Pointer to the size of the trimmed test case
- */
-size_t afl_custom_trim(my_mutator_t *data, uint8_t **out_buf) {
-
- *out_buf = data->trim_buf;
-
- // Remove the last byte of the trimming input
- return data->trim_size_current - 1;
-
-}
-
-/**
- * This method is called after each trim operation to inform you if your
- * trimming step was successful or not (in terms of coverage). If you receive
- * a failure here, you should reset your input to the last known good state.
- *
- * (Optional)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param success Indicates if the last trim operation was successful.
- * @return The next trim iteration index (from 0 to the maximum amount of
- * steps returned in init_trim). negative ret on failure.
- */
-int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
-
- if (success) {
-
- ++data->cur_step;
- return data->cur_step;
-
- }
-
- return data->trimmming_steps;
-
-}
-
-/**
- * Perform a single custom mutation on a given input.
- * This mutation is stacked with the other muatations in havoc.
- *
- * (Optional)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param[in] buf Pointer to the input data to be mutated and the mutated
- * output
- * @param[in] buf_size Size of input data
- * @param[out] out_buf The output buffer. buf can be reused, if the content
- * fits. *out_buf = NULL is treated as error.
- * @param[in] max_size Maximum size of the mutated output. The mutation must
- * not produce data larger than max_size.
- * @return Size of the mutated output.
- */
-size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
- u8 **out_buf, size_t max_size) {
-
- if (buf_size == 0) {
-
- *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
- if (!*out_buf) {
-
- perror("custom havoc: maybe_grow");
- return 0;
-
- }
-
- **out_buf = rand() % 256;
- buf_size = 1;
-
- } else {
-
- // We reuse buf here. It's legal and faster.
- *out_buf = buf;
-
- }
-
- size_t victim = rand() % buf_size;
- (*out_buf)[victim] += rand() % 10;
-
- return buf_size;
-
-}
-
-/**
- * Return the probability (in percentage) that afl_custom_havoc_mutation
- * is called in havoc. By default it is 6 %.
- *
- * (Optional)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @return The probability (0-100).
- */
-uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
-
- return 5; // 5 %
-
-}
-
-/**
- * Determine whether the fuzzer should fuzz the queue entry or not.
- *
- * (Optional)
- *
- * @param[in] data pointer returned in afl_custom_init for this fuzz case
- * @param filename File name of the test case in the queue entry
- * @return Return True(1) if the fuzzer will fuzz the queue entry, and
- * False(0) otherwise.
- */
-uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
-
- return 1;
-
-}
-
-/**
- * Allow for additional analysis (e.g. calling a different tool that does a
- * different kind of coverage and saves this for the custom mutator).
- *
- * (Optional)
- *
- * @param data pointer returned in afl_custom_init for this fuzz case
- * @param filename_new_queue File name of the new queue entry
- * @param filename_orig_queue File name of the original queue entry
- */
-void afl_custom_queue_new_entry(my_mutator_t * data,
- const uint8_t *filename_new_queue,
- const uint8_t *filename_orig_queue) {
-
- /* Additional analysis on the original or new test case */
-
-}
-
-/**
- * Deinitialize everything
- *
- * @param data The data ptr from afl_custom_init
- */
-void afl_custom_deinit(my_mutator_t *data) {
-
- free(data->post_process_buf);
- free(data->havoc_buf);
- free(data->data_buf);
- free(data->fuzz_buf);
- free(data->trim_buf);
- free(data);
-
-}
-
diff --git a/examples/custom_mutators/example.py b/examples/custom_mutators/example.py
deleted file mode 100644
index cf659e5a..00000000
--- a/examples/custom_mutators/example.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-'''
-Example Python Module for AFLFuzz
-
-@author: Christian Holler (:decoder)
-
-@license:
-
-This Source Code Form is subject to the terms of the Mozilla Public
-License, v. 2.0. If a copy of the MPL was not distributed with this
-file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-@contact: choller@mozilla.com
-'''
-
-import random
-
-
-COMMANDS = [
- b"GET",
- b"PUT",
- b"DEL",
- b"AAAAAAAAAAAAAAAAA",
-]
-
-
-def init(seed):
- '''
- Called once when AFLFuzz starts up. Used to seed our RNG.
-
- @type seed: int
- @param seed: A 32-bit random value
- '''
- random.seed(seed)
-
-
-def deinit():
- pass
-
-
-def fuzz(buf, add_buf, max_size):
- '''
- Called per fuzzing iteration.
-
- @type buf: bytearray
- @param buf: The buffer that should be mutated.
-
- @type add_buf: bytearray
- @param add_buf: A second buffer that can be used as mutation source.
-
- @type max_size: int
- @param max_size: Maximum size of the mutated output. The mutation must not
- produce data larger than max_size.
-
- @rtype: bytearray
- @return: A new bytearray containing the mutated data
- '''
- ret = bytearray(100)
-
- ret[:3] = random.choice(COMMANDS)
-
- return ret
-
-# Uncomment and implement the following methods if you want to use a custom
-# trimming algorithm. See also the documentation for a better API description.
-
-# def init_trim(buf):
-# '''
-# Called per trimming iteration.
-#
-# @type buf: bytearray
-# @param buf: The buffer that should be trimmed.
-#
-# @rtype: int
-# @return: The maximum number of trimming steps.
-# '''
-# global ...
-#
-# # Initialize global variables
-#
-# # Figure out how many trimming steps are possible.
-# # If this is not possible for your trimming, you can
-# # return 1 instead and always return 0 in post_trim
-# # until you are done (then you return 1).
-#
-# return steps
-#
-# def trim():
-# '''
-# Called per trimming iteration.
-#
-# @rtype: bytearray
-# @return: A new bytearray containing the trimmed data.
-# '''
-# global ...
-#
-# # Implement the actual trimming here
-#
-# return bytearray(...)
-#
-# def post_trim(success):
-# '''
-# Called after each trimming operation.
-#
-# @type success: bool
-# @param success: Indicates if the last trim operation was successful.
-#
-# @rtype: int
-# @return: The next trim index (0 to max number of steps) where max
-# number of steps indicates the trimming is done.
-# '''
-# global ...
-#
-# if not success:
-# # Restore last known successful input, determine next index
-# else:
-# # Just determine the next index, based on what was successfully
-# # removed in the last step
-#
-# return next_index
-#
-# def post_process(buf):
-# '''
-# Called just before the execution to write the test case in the format
-# expected by the target
-#
-# @type buf: bytearray
-# @param buf: The buffer containing the test case to be executed
-#
-# @rtype: bytearray
-# @return: The buffer containing the test case after
-# '''
-# return buf
-#
-# def havoc_mutation(buf, max_size):
-# '''
-# Perform a single custom mutation on a given input.
-#
-# @type buf: bytearray
-# @param buf: The buffer that should be mutated.
-#
-# @type max_size: int
-# @param max_size: Maximum size of the mutated output. The mutation must not
-# produce data larger than max_size.
-#
-# @rtype: bytearray
-# @return: A new bytearray containing the mutated data
-# '''
-# return mutated_buf
-#
-# def havoc_mutation_probability():
-# '''
-# Called for each `havoc_mutation`. Return the probability (in percentage)
-# that `havoc_mutation` is called in havoc. Be default it is 6%.
-#
-# @rtype: int
-# @return: The probability (0-100)
-# '''
-# return prob
-#
-# def queue_get(filename):
-# '''
-# Called at the beginning of each fuzz iteration to determine whether the
-# test case should be fuzzed
-#
-# @type filename: str
-# @param filename: File name of the test case in the current queue entry
-#
-# @rtype: bool
-# @return: Return True if the custom mutator decides to fuzz the test case,
-# and False otherwise
-# '''
-# return True
-#
-# def queue_new_entry(filename_new_queue, filename_orig_queue):
-# '''
-# Called after adding a new test case to the queue
-#
-# @type filename_new_queue: str
-# @param filename_new_queue: File name of the new queue entry
-#
-# @type filename_orig_queue: str
-# @param filename_orig_queue: File name of the original queue entry
-# '''
-# pass
diff --git a/examples/custom_mutators/post_library_gif.so.c b/examples/custom_mutators/post_library_gif.so.c
deleted file mode 100644
index ac10f409..00000000
--- a/examples/custom_mutators/post_library_gif.so.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- american fuzzy lop++ - postprocessor library example
- --------------------------------------------------
-
- Originally written by Michal Zalewski
- Edited by Dominik Maier, 2020
-
- Copyright 2015 Google Inc. All rights reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at:
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Postprocessor libraries can be passed to afl-fuzz to perform final cleanup
- of any mutated test cases - for example, to fix up checksums in PNG files.
-
- Please heed the following warnings:
-
- 1) In almost all cases, it is more productive to comment out checksum logic
- in the targeted binary (as shown in ../libpng_no_checksum/). One possible
- exception is the process of fuzzing binary-only software in QEMU mode.
-
- 2) The use of postprocessors for anything other than checksums is
- questionable and may cause more harm than good. AFL is normally pretty good
- about dealing with length fields, magic values, etc.
-
- 3) Postprocessors that do anything non-trivial must be extremely robust to
- gracefully handle malformed data and other error conditions - otherwise,
- they will crash and take afl-fuzz down with them. Be wary of reading past
- *len and of integer overflows when calculating file offsets.
-
- In other words, THIS IS PROBABLY NOT WHAT YOU WANT - unless you really,
- honestly know what you're doing =)
-
- With that out of the way: the postprocessor library is passed to afl-fuzz
- via AFL_POST_LIBRARY. The library must be compiled with:
-
- gcc -shared -Wall -O3 post_library.so.c -o post_library.so
-
- AFL will call the afl_custom_post_process() function for every mutated output
- buffer. From there, you have three choices:
-
- 1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
- and return the original `len`.
-
- 2) If you want to skip this test case altogether and have AFL generate a
- new one, return 0 or set `*out_buf = NULL`.
- Use this sparingly - it's faster than running the target program
- with patently useless inputs, but still wastes CPU time.
-
- 3) If you want to modify the test case, allocate an appropriately-sized
- buffer, move the data into that buffer, make the necessary changes, and
- then return the new pointer as out_buf. Return an appropriate len
- afterwards.
-
- Note that the buffer will *not* be freed for you. To avoid memory leaks,
- you need to free it or reuse it on subsequent calls (as shown below).
-
- *** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
-
- Aight. The example below shows a simple postprocessor that tries to make
- sure that all input files start with "GIF89a".
-
- PS. If you don't like C, you can try out the unix-based wrapper from
- Ben Nagy instead: https://github.com/bnagy/aflfix
-
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Header that must be present at the beginning of every test case: */
-
-#define HEADER "GIF89a"
-
-typedef struct post_state {
-
- unsigned char *buf;
- size_t size;
-
-} post_state_t;
-
-void *afl_custom_init(void *afl) {
-
- post_state_t *state = malloc(sizeof(post_state_t));
- if (!state) {
-
- perror("malloc");
- return NULL;
-
- }
-
- state->buf = calloc(sizeof(unsigned char), 4096);
- if (!state->buf) {
-
- free(state);
- perror("calloc");
- return NULL;
-
- }
-
- return state;
-
-}
-
-/* The actual postprocessor routine called by afl-fuzz: */
-
-size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
- unsigned int len, unsigned char **out_buf) {
-
- /* Skip execution altogether for buffers shorter than 6 bytes (just to
- show how it's done). We can trust len to be sane. */
-
- if (len < strlen(HEADER)) return 0;
-
- /* Do nothing for buffers that already start with the expected header. */
-
- if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- /* Allocate memory for new buffer, reusing previous allocation if
- possible. */
-
- *out_buf = realloc(data->buf, len);
-
- /* If we're out of memory, the most graceful thing to do is to return the
- original buffer and give up on modifying it. Let AFL handle OOM on its
- own later on. */
-
- if (!*out_buf) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- /* Copy the original data to the new location. */
-
- memcpy(*out_buf, in_buf, len);
-
- /* Insert the new header. */
-
- memcpy(*out_buf, HEADER, strlen(HEADER));
-
- /* Return the new len. It hasn't changed, so it's just len. */
-
- return len;
-
-}
-
-/* Gets called afterwards */
-void afl_custom_deinit(post_state_t *data) {
-
- free(data->buf);
- free(data);
-
-}
-
diff --git a/examples/custom_mutators/post_library_png.so.c b/examples/custom_mutators/post_library_png.so.c
deleted file mode 100644
index 941f7e55..00000000
--- a/examples/custom_mutators/post_library_png.so.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- american fuzzy lop++ - postprocessor for PNG
- ------------------------------------------
-
- Originally written by Michal Zalewski
-
- Copyright 2015 Google Inc. All rights reserved.
- Adapted to the new API, 2020 by Dominik Maier
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at:
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- See post_library.so.c for a general discussion of how to implement
- postprocessors. This specific postprocessor attempts to fix up PNG
- checksums, providing a slightly more complicated example than found
- in post_library.so.c.
-
- Compile with:
-
- gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz
-
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <zlib.h>
-
-#include <arpa/inet.h>
-
-/* A macro to round an integer up to 4 kB. */
-
-#define UP4K(_i) ((((_i) >> 12) + 1) << 12)
-
-typedef struct post_state {
-
- unsigned char *buf;
- size_t size;
-
-} post_state_t;
-
-void *afl_custom_init(void *afl) {
-
- post_state_t *state = malloc(sizeof(post_state_t));
- if (!state) {
-
- perror("malloc");
- return NULL;
-
- }
-
- state->buf = calloc(sizeof(unsigned char), 4096);
- if (!state->buf) {
-
- free(state);
- perror("calloc");
- return NULL;
-
- }
-
- return state;
-
-}
-
-size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
- unsigned int len,
- const unsigned char **out_buf) {
-
- unsigned char *new_buf = (unsigned char *)in_buf;
- unsigned int pos = 8;
-
- /* Don't do anything if there's not enough room for the PNG header
- (8 bytes). */
-
- if (len < 8) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- /* Minimum size of a zero-length PNG chunk is 12 bytes; if we
- don't have that, we can bail out. */
-
- while (pos + 12 <= len) {
-
- unsigned int chunk_len, real_cksum, file_cksum;
-
- /* Chunk length is the first big-endian dword in the chunk. */
-
- chunk_len = ntohl(*(uint32_t *)(in_buf + pos));
-
- /* Bail out if chunk size is too big or goes past EOF. */
-
- if (chunk_len > 1024 * 1024 || pos + 12 + chunk_len > len) break;
-
- /* Chunk checksum is calculated for chunk ID (dword) and the actual
- payload. */
-
- real_cksum = htonl(crc32(0, in_buf + pos + 4, chunk_len + 4));
-
- /* The in-file checksum is the last dword past the chunk data. */
-
- file_cksum = *(uint32_t *)(in_buf + pos + 8 + chunk_len);
-
- /* If the checksums do not match, we need to fix the file. */
-
- if (real_cksum != file_cksum) {
-
- /* First modification? Make a copy of the input buffer. Round size
- up to 4 kB to minimize the number of reallocs needed. */
-
- if (new_buf == in_buf) {
-
- if (len <= data->size) {
-
- new_buf = data->buf;
-
- } else {
-
- new_buf = realloc(data->buf, UP4K(len));
- if (!new_buf) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- data->buf = new_buf;
- data->size = UP4K(len);
- memcpy(new_buf, in_buf, len);
-
- }
-
- }
-
- *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
-
- }
-
- /* Skip the entire chunk and move to the next one. */
-
- pos += 12 + chunk_len;
-
- }
-
- *out_buf = new_buf;
- return len;
-
-}
-
-/* Gets called afterwards */
-void afl_custom_deinit(post_state_t *data) {
-
- free(data->buf);
- free(data);
-
-}
-
diff --git a/examples/custom_mutators/simple-chunk-replace.py b/examples/custom_mutators/simple-chunk-replace.py
deleted file mode 100644
index df2f4ca7..00000000
--- a/examples/custom_mutators/simple-chunk-replace.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-'''
-Simple Chunk Cross-Over Replacement Module for AFLFuzz
-
-@author: Christian Holler (:decoder)
-
-@license:
-
-This Source Code Form is subject to the terms of the Mozilla Public
-License, v. 2.0. If a copy of the MPL was not distributed with this
-file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-@contact: choller@mozilla.com
-'''
-
-import random
-
-
-def init(seed):
- '''
- Called once when AFLFuzz starts up. Used to seed our RNG.
-
- @type seed: int
- @param seed: A 32-bit random value
- '''
- # Seed our RNG
- random.seed(seed)
-
-
-def fuzz(buf, add_buf, max_size):
- '''
- Called per fuzzing iteration.
-
- @type buf: bytearray
- @param buf: The buffer that should be mutated.
-
- @type add_buf: bytearray
- @param add_buf: A second buffer that can be used as mutation source.
-
- @type max_size: int
- @param max_size: Maximum size of the mutated output. The mutation must not
- produce data larger than max_size.
-
- @rtype: bytearray
- @return: A new bytearray containing the mutated data
- '''
- # Make a copy of our input buffer for returning
- ret = bytearray(buf)
-
- # Take a random fragment length between 2 and 32 (or less if add_buf is shorter)
- fragment_len = random.randint(1, min(len(add_buf), 32))
-
- # Determine a random source index where to take the data chunk from
- rand_src_idx = random.randint(0, len(add_buf) - fragment_len)
-
- # Determine a random destination index where to put the data chunk
- rand_dst_idx = random.randint(0, len(buf))
-
- # Make the chunk replacement
- ret[rand_dst_idx:rand_dst_idx + fragment_len] = add_buf[rand_src_idx:rand_src_idx + fragment_len]
-
- # Return data
- return ret
diff --git a/examples/custom_mutators/simple_example.c b/examples/custom_mutators/simple_example.c
deleted file mode 100644
index d888ec1f..00000000
--- a/examples/custom_mutators/simple_example.c
+++ /dev/null
@@ -1,74 +0,0 @@
-// This simple example just creates random buffer <= 100 filled with 'A'
-// needs -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#ifndef _FIXED_CHAR
- #define _FIXED_CHAR 0x41
-#endif
-
-typedef struct my_mutator {
-
- afl_t *afl;
-
- // Reused buffers:
- BUF_VAR(u8, fuzz);
-
-} my_mutator_t;
-
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
-
- srand(seed);
- my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
- if (!data) {
-
- perror("afl_custom_init alloc");
- return NULL;
-
- }
-
- data->afl = afl;
-
- return data;
-
-}
-
-size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
- u8 **out_buf, uint8_t *add_buf,
- size_t add_buf_size, // add_buf can be NULL
- size_t max_size) {
-
- int size = (rand() % 100) + 1;
- if (size > max_size) size = max_size;
- u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
- if (!mutated_out) {
-
- *out_buf = NULL;
- perror("custom mutator allocation (maybe_grow)");
- return 0; /* afl-fuzz will very likely error out after this. */
-
- }
-
- memset(mutated_out, _FIXED_CHAR, size);
-
- *out_buf = mutated_out;
- return size;
-
-}
-
-/**
- * Deinitialize everything
- *
- * @param data The data ptr from afl_custom_init
- */
-void afl_custom_deinit(my_mutator_t *data) {
-
- free(data->fuzz_buf);
- free(data);
-
-}
-
diff --git a/examples/custom_mutators/wrapper_afl_min.py b/examples/custom_mutators/wrapper_afl_min.py
deleted file mode 100644
index ecb03b55..00000000
--- a/examples/custom_mutators/wrapper_afl_min.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-
-from XmlMutatorMin import XmlMutatorMin
-
-# Default settings (production mode)
-
-__mutator__ = None
-__seed__ = "RANDOM"
-__log__ = False
-__log_file__ = "wrapper.log"
-
-
-# AFL functions
-def log(text):
- """
- Logger
- """
-
- global __seed__
- global __log__
- global __log_file__
-
- if __log__:
- with open(__log_file__, "a") as logf:
- logf.write("[%s] %s\n" % (__seed__, text))
-
-
-def init(seed):
- """
- Called once when AFL starts up. Seed is used to identify the AFL instance in log files
- """
-
- global __mutator__
- global __seed__
-
- # Get the seed
- __seed__ = seed
-
- # Create a global mutation class
- try:
- __mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
- log("init(): Mutator created")
- except RuntimeError as e:
- log("init(): Can't create mutator: %s" % e.message)
-
-
-def fuzz(buf, add_buf, max_size):
- """
- Called for each fuzzing iteration.
- """
-
- global __mutator__
-
- # Do we have a working mutator object?
- if __mutator__ is None:
- log("fuzz(): Can't fuzz, no mutator available")
- return buf
-
- # Try to use the AFL buffer
- via_buffer = True
-
- # Interpret the AFL buffer (an array of bytes) as a string
- if via_buffer:
- try:
- buf_str = str(buf)
- log("fuzz(): AFL buffer converted to a string")
- except Exception:
- via_buffer = False
- log("fuzz(): Can't convert AFL buffer to a string")
-
- # Load XML from the AFL string
- if via_buffer:
- try:
- __mutator__.init_from_string(buf_str)
- log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
- except Exception:
- via_buffer = False
- log("fuzz(): Can't initialize mutator with AFL buffer")
-
- # If init from AFL buffer wasn't succesful
- if not via_buffer:
- log("fuzz(): Returning unmodified AFL buffer")
- return buf
-
- # Sucessful initialization -> mutate
- try:
- __mutator__.mutate(max=5)
- log("fuzz(): Input mutated")
- except Exception:
- log("fuzz(): Can't mutate input => returning buf")
- return buf
-
- # Convert mutated data to a array of bytes
- try:
- data = bytearray(__mutator__.save_to_string())
- log("fuzz(): Mutated data converted as bytes")
- except Exception:
- log("fuzz(): Can't convert mutated data to bytes => returning buf")
- return buf
-
- # Everything went fine, returning mutated content
- log("fuzz(): Returning %d bytes" % len(data))
- return data
-
-
-# Main (for debug)
-if __name__ == '__main__':
-
- __log__ = True
- __log_file__ = "/dev/stdout"
- __seed__ = "RANDOM"
-
- init(__seed__)
-
- in_1 = bytearray("<foo ddd='eeee'>ffff<a b='c' d='456' eee='ffffff'>zzzzzzzzzzzz</a><b yyy='YYY' zzz='ZZZ'></b></foo>")
- in_2 = bytearray("<abc abc123='456' abcCBA='ppppppppppppppppppppppppppppp'/>")
- out = fuzz(in_1, in_2)
- print(out)