about summary refs log tree commit diff
path: root/examples
diff options
context:
space:
mode:
authorAndrea Fioraldi <andreafioraldi@gmail.com>2020-02-03 13:11:10 +0100
committerAndrea Fioraldi <andreafioraldi@gmail.com>2020-02-03 13:11:10 +0100
commit2fe7889912c9bb340f302a037585b7b1836ac94f (patch)
tree5c3e4e5829f45dce46794ebc2681732738d689fe /examples
parente2eedefc65bec1a04605f117a11ca8bdf9d80323 (diff)
downloadafl++-2fe7889912c9bb340f302a037585b7b1836ac94f.tar.gz
move custom and pythoon mutators examples into examples/
Diffstat (limited to 'examples')
-rw-r--r--examples/README.md47
-rw-r--r--examples/argv_fuzzing/Makefile41
-rw-r--r--examples/argv_fuzzing/README.md16
-rw-r--r--examples/argv_fuzzing/argv-fuzz-inl.h90
-rw-r--r--examples/argv_fuzzing/argvfuzz.c49
-rwxr-xr-xexamples/asan_cgroups/limit_memory.sh157
-rw-r--r--examples/bash_shellshock/shellshock-fuzz.diff59
-rw-r--r--examples/canvas_harness/canvas_harness.html170
-rwxr-xr-xexamples/clang_asm_normalize/as75
-rwxr-xr-xexamples/crash_triage/triage_crashes.sh115
-rw-r--r--examples/custom_mutators/README2
-rw-r--r--examples/custom_mutators/simple_mutator.c49
-rwxr-xr-xexamples/distributed_fuzzing/sync_script.sh94
-rw-r--r--examples/libpng_no_checksum/libpng-nocrc.patch15
-rw-r--r--examples/persistent_demo/persistent_demo.c101
-rw-r--r--examples/post_library/post_library.so.c120
-rw-r--r--examples/post_library/post_library_png.so.c114
-rw-r--r--examples/python_mutators/README18
-rw-r--r--examples/python_mutators/XmlMutatorMin.py331
-rw-r--r--examples/python_mutators/common.py37
-rw-r--r--examples/python_mutators/example.py103
-rw-r--r--examples/python_mutators/simple-chunk-replace.py59
-rw-r--r--examples/python_mutators/wrapper_afl_min.py117
-rw-r--r--examples/socket_fuzzing/Makefile39
-rw-r--r--examples/socket_fuzzing/README.md11
-rw-r--r--examples/socket_fuzzing/socketfuzz.c110
26 files changed, 2139 insertions, 0 deletions
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 00000000..512b03f7
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,47 @@
+# AFL++ Examples
+
+Here's a quick overview of the stuff you can find in this directory:
+
+  - custom_mutstors      - An example custom mutator
+  
+  - python_mutators      - Python mutators examples
+
+  - argv_fuzzing         - a simple wrapper to allow cmdline to be fuzzed
+                           (e.g., to test setuid programs).
+
+  - asan_cgroups         - a contributed script to simplify fuzzing ASAN
+                           binaries with robust memory limits on Linux.
+
+  - bash_shellshock      - a simple hack used to find a bunch of
+                           post-Shellshock bugs in bash.
+
+  - canvas_harness       - a test harness used to find browser bugs with a 
+                           corpus generated using simple image parsing 
+                           binaries & afl-fuzz.
+
+  - clang_asm_normalize  - a script that makes it easy to instrument
+                           hand-written assembly, provided that you have clang.
+
+  - crash_triage         - a very rudimentary example of how to annotate crashes
+                           with additional gdb metadata.
+
+  - distributed_fuzzing  - a sample script for synchronizing fuzzer instances
+                           across multiple machines (see parallel_fuzzing.md).
+
+  - libpng_no_checksum   - a sample patch for removing CRC checks in libpng.
+
+  - persistent_demo      - an example of how to use the LLVM persistent process
+                           mode to speed up certain fuzzing jobs.
+
+  - post_library         - an example of how to build postprocessors for AFL.
+  
+  - socket_fuzzing       - a LD_PRELOAD library 'redirects' a socket to stdin
+                           for fuzzing access with afl++
+
+Note that the minimize_corpus.sh tool has graduated from the experimental/
+directory and is now available as ../afl-cmin. The LLVM mode has likewise
+graduated to ../llvm_mode/*.
+
+Most of the tools in this directory are meant chiefly as examples that need to
+be tweaked for your specific needs. They come with some basic documentation,
+but are not necessarily production-grade.
diff --git a/examples/argv_fuzzing/Makefile b/examples/argv_fuzzing/Makefile
new file mode 100644
index 00000000..ab16be87
--- /dev/null
+++ b/examples/argv_fuzzing/Makefile
@@ -0,0 +1,41 @@
+#
+# american fuzzy lop++ - argvfuzz
+# --------------------------------
+#
+# Copyright 2019-2020 Kjell Braden <afflux@pentabarf.de>
+#
+# 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
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+ifneq "$(filter Linux GNU%,$(shell uname))" ""
+  LDFLAGS  += -ldl
+endif
+
+all: argvfuzz32.so argvfuzz64.so
+
+argvfuzz32.so: argvfuzz.c
+	-$(CC) -m32 $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "argvfuzz32 build failure (that's fine)"
+
+argvfuzz64.so: argvfuzz.c
+	-$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+install: argvfuzz32.so argvfuzz64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f argvfuzz32.so ]; then set -e; install -m 755 argvfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	install -m 755 argvfuzz64.so $(DESTDIR)$(HELPER_PATH)/
+
+clean:
+	rm -f argvfuzz32.so argvfuzz64.so
diff --git a/examples/argv_fuzzing/README.md b/examples/argv_fuzzing/README.md
new file mode 100644
index 00000000..fa8cad80
--- /dev/null
+++ b/examples/argv_fuzzing/README.md
@@ -0,0 +1,16 @@
+# argvfuzz
+
+afl supports fuzzing file inputs or stdin. When source is available,
+`argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin.
+
+`argvfuzz` tries to provide the same functionality for binaries. When loaded
+using `LD_PRELOAD`, it will hook the call to `__libc_start_main` and replace
+argv using the same logic of `argv-fuzz-inl.h`.
+
+A few conditions need to be fulfilled for this mechanism to work correctly:
+
+1. As it relies on hooking the loader, it cannot work on static binaries.
+2. If the target binary does not use the default libc's `_start` implementation
+   (crt1.o), the hook may not run.
+3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the
+   target binary expects argv to be living on the stack, things may go wrong.
diff --git a/examples/argv_fuzzing/argv-fuzz-inl.h b/examples/argv_fuzzing/argv-fuzz-inl.h
new file mode 100644
index 00000000..4d880020
--- /dev/null
+++ b/examples/argv_fuzzing/argv-fuzz-inl.h
@@ -0,0 +1,90 @@
+/*
+   american fuzzy lop++ - sample argv fuzzing wrapper
+   ------------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   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
+
+   This file shows a simple way to fuzz command-line parameters with stock
+   afl-fuzz. To use, add:
+
+   #include "/path/to/argv-fuzz-inl.h"
+
+   ...to the file containing main(), ideally placing it after all the
+   standard includes. Next, put AFL_INIT_ARGV(); near the very beginning of
+   main().
+
+   This will cause the program to read NUL-delimited input from stdin and
+   put it in argv[]. Two subsequent NULs terminate the array. Empty
+   params are encoded as a lone 0x02. Lone 0x02 can't be generated, but
+   that shouldn't matter in real life.
+
+   If you would like to always preserve argv[0], use this instead:
+   AFL_INIT_SET0("prog_name");
+
+*/
+
+#ifndef _HAVE_ARGV_FUZZ_INL
+#define _HAVE_ARGV_FUZZ_INL
+
+#include <unistd.h>
+
+#define AFL_INIT_ARGV()          \
+  do {                           \
+                                 \
+    argv = afl_init_argv(&argc); \
+                                 \
+  } while (0)
+
+#define AFL_INIT_SET0(_p)        \
+  do {                           \
+                                 \
+    argv = afl_init_argv(&argc); \
+    argv[0] = (_p);              \
+    if (!argc) argc = 1;         \
+                                 \
+  } while (0)
+
+#define MAX_CMDLINE_LEN 100000
+#define MAX_CMDLINE_PAR 1000
+
+static char** afl_init_argv(int* argc) {
+
+  static char  in_buf[MAX_CMDLINE_LEN];
+  static char* ret[MAX_CMDLINE_PAR];
+
+  char* ptr = in_buf;
+  int   rc = 0;
+
+  if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {}
+
+  while (*ptr) {
+
+    ret[rc] = ptr;
+    if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++;
+    rc++;
+
+    while (*ptr)
+      ptr++;
+    ptr++;
+
+  }
+
+  *argc = rc;
+
+  return ret;
+
+}
+
+#undef MAX_CMDLINE_LEN
+#undef MAX_CMDLINE_PAR
+
+#endif                                              /* !_HAVE_ARGV_FUZZ_INL */
+
diff --git a/examples/argv_fuzzing/argvfuzz.c b/examples/argv_fuzzing/argvfuzz.c
new file mode 100644
index 00000000..4251ca4c
--- /dev/null
+++ b/examples/argv_fuzzing/argvfuzz.c
@@ -0,0 +1,49 @@
+/*
+   american fuzzy lop++ - LD_PRELOAD for fuzzing argv in binaries
+   ------------------------------------------------------------
+
+   Copyright 2019-2020 Kjell Braden <afflux@pentabarf.de>
+
+   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
+
+ */
+
+#define _GNU_SOURCE                                        /* for RTLD_NEXT */
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "argv-fuzz-inl.h"
+
+int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
+                      void (*init)(void), void (*fini)(void),
+                      void (*rtld_fini)(void), void *stack_end) {
+
+  int (*orig)(int (*main)(int, char **, char **), int argc, char **argv,
+              void (*init)(void), void (*fini)(void), void (*rtld_fini)(void),
+              void *stack_end);
+  int    sub_argc;
+  char **sub_argv;
+
+  (void)argc;
+  (void)argv;
+
+  orig = dlsym(RTLD_NEXT, __func__);
+
+  if (!orig) {
+
+    fprintf(stderr, "hook did not find original %s: %s\n", __func__, dlerror());
+    exit(EXIT_FAILURE);
+
+  }
+
+  sub_argv = afl_init_argv(&sub_argc);
+
+  return orig(main, sub_argc, sub_argv, init, fini, rtld_fini, stack_end);
+
+}
+
diff --git a/examples/asan_cgroups/limit_memory.sh b/examples/asan_cgroups/limit_memory.sh
new file mode 100755
index 00000000..ac3a90fe
--- /dev/null
+++ b/examples/asan_cgroups/limit_memory.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+#
+# american fuzzy lop++ - limit memory using cgroups
+# -----------------------------------------------
+#
+# Written by Samir Khakimov <samir.hakim@nyu.edu> and
+#            David A. Wheeler <dwheeler@ida.org>
+#
+# Edits to bring the script in line with afl-cmin and other companion scripts
+# by Michal Zalewski. All bugs are my fault.
+#
+# Copyright 2015 Institute for Defense Analyses.
+#
+# 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
+#
+# This tool allows the amount of actual memory allocated to a program
+# to be limited on Linux systems using cgroups, instead of the traditional
+# setrlimit() API. This helps avoid the address space problems discussed in
+# docs/notes_for_asan.txt.
+#
+# Important: the limit covers *both* afl-fuzz and the fuzzed binary. In some
+# hopefully rare circumstances, afl-fuzz could be killed before the fuzzed
+# task.
+#
+
+echo "cgroup tool for afl-fuzz by <samir.hakim@nyu.edu> and <dwheeler@ida.org>"
+echo
+
+unset NEW_USER
+MEM_LIMIT="50"
+
+while getopts "+u:m:" opt; do
+
+  case "$opt" in
+
+    "u")
+         NEW_USER="$OPTARG"
+         ;;
+
+    "m")
+         MEM_LIMIT="$[OPTARG]"
+         ;;
+
+    "?")
+         exit 1
+         ;;
+
+   esac
+
+done
+
+if [ "$MEM_LIMIT" -lt "5" ]; then
+  echo "[-] Error: malformed or dangerously low value of -m." 1>&2
+  exit 1
+fi
+
+shift $((OPTIND-1))
+
+TARGET_BIN="$1"
+
+if [ "$TARGET_BIN" = "" -o "$NEW_USER" = "" ]; then
+
+  cat 1>&2 <<_EOF_
+Usage: $0 [ options ] -- /path/to/afl-fuzz [ ...afl options... ]
+
+Required parameters:
+
+  -u user   - run the fuzzer as a specific user after setting up limits
+
+Optional parameters:
+
+  -m megs   - set memory limit to a specified value ($MEM_LIMIT MB)
+
+This tool configures cgroups-based memory limits for a fuzzing job to simplify
+the task of fuzzing ASAN or MSAN binaries. You would normally want to use it in
+conjunction with '-m none' passed to the afl-fuzz binary itself, say:
+
+  $0 -u joe ./afl-fuzz -i input -o output -m none /path/to/target
+
+_EOF_
+
+  exit 1
+
+fi
+
+# Basic sanity checks
+
+if [ ! "`uname -s`" = "Linux" ]; then
+ echo "[-] Error: this tool does not support non-Linux systems." 1>&2
+ exit 1
+fi
+
+if [ ! "`id -u`" = "0" ]; then
+ echo "[-] Error: you need to run this script as root (sorry!)." 1>&2
+ exit 1
+fi
+
+if ! type cgcreate 2>/dev/null 1>&2; then
+
+  echo "[-] Error: you need to install cgroup tools first." 1>&2
+
+  if type apt-get 2>/dev/null 1>&2; then
+    echo "    (Perhaps 'apt-get install cgroup-bin' will work.)" 1>&2
+  elif type yum 2>/dev/null 1>&2; then
+    echo "    (Perhaps 'yum install libcgroup-tools' will work.)" 1>&2
+  fi
+
+  exit 1
+
+fi
+
+if ! id -u "$NEW_USER" 2>/dev/null 1>&2; then
+  echo "[-] Error: user '$NEW_USER' does not seem to exist." 1>&2
+  exit 1
+fi
+
+# Create a new cgroup path if necessary... We used PID-keyed groups to keep
+# parallel afl-fuzz tasks separate from each other.
+
+CID="afl-$NEW_USER-$$"
+
+CPATH="/sys/fs/cgroup/memory/$CID"
+
+if [ ! -d "$CPATH" ]; then
+
+  cgcreate -a "$NEW_USER" -g memory:"$CID" || exit 1
+
+fi
+
+# Set the appropriate limit...
+
+if [ -f "$CPATH/memory.memsw.limit_in_bytes" ]; then
+
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" 2>/dev/null
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.memsw.limit_in_bytes" || exit 1
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+elif grep -qE 'partition|file' /proc/swaps; then
+
+  echo "[-] Error: your system requires swap to be disabled first (swapoff -a)." 1>&2
+  exit 1
+
+else
+
+  echo "${MEM_LIMIT}M" > "$CPATH/memory.limit_in_bytes" || exit 1
+
+fi
+
+# All right. At this point, we can just run the command.
+
+cgexec -g "memory:$CID" su -c "$*" "$NEW_USER"
+
+cgdelete -g "memory:$CID"
diff --git a/examples/bash_shellshock/shellshock-fuzz.diff b/examples/bash_shellshock/shellshock-fuzz.diff
new file mode 100644
index 00000000..3fa05bf8
--- /dev/null
+++ b/examples/bash_shellshock/shellshock-fuzz.diff
@@ -0,0 +1,59 @@
+This patch shows a very simple way to find post-Shellshock bugs in bash, as
+discussed here:
+
+  http://lcamtuf.blogspot.com/2014/10/bash-bug-how-we-finally-cracked.html
+
+In essence, it shows a way to fuzz environmental variables. Instructions:
+
+1) Download bash 4.3, apply this patch, compile with:
+
+   CC=/path/to/afl-gcc ./configure
+   make clean all
+
+   Note that the harness puts the fuzzed output in $TEST_VARIABLE. With
+   Florian's Shellshock patch (bash43-028), this is no longer passed down
+   to the parser.
+
+2) Create and cd to an empty directory, put the compiled bash binary in
+   there, and run these commands:
+
+   mkdir in_dir
+   echo -n '() { a() { a; }; : >b; }' >in_dir/script.txt
+
+3) Run the fuzzer with:
+
+   /path/to/afl-fuzz -d -i in_dir -o out_dir ./bash -c :
+
+   The -d parameter is advisable only if the tested shell is fairly slow
+   or if you are in a hurry; will cover more ground faster, but
+   less systematically.
+
+4) Watch for crashes in out_dir/crashes/. Also watch for any new files
+   created in cwd if you're interested in non-crash RCEs (files will be
+   created whenever the shell executes "foo>bar" or something like
+   that). You can correlate their creation date with new entries in
+   out_dir/queue/.
+
+   You can also modify the bash binary to directly check for more subtle
+   fault conditions, or use the synthesized entries in out_dir/queue/
+   as a seed for other, possibly slower or more involved testing regimes.
+
+   Expect several hours to get decent coverage.
+
+--- bash-4.3/shell.c.orig	2014-01-14 14:04:32.000000000 +0100
++++ bash-4.3/shell.c	2015-04-30 05:56:46.000000000 +0200
+@@ -371,6 +371,14 @@
+   env = environ;
+ #endif /* __OPENNT */
+ 
++  {
++
++    static char val[1024 * 16];
++    read(0, val, sizeof(val) - 1);
++    setenv("TEST_VARIABLE", val, 1);
++
++  }
++
+   USE_VAR(argc);
+   USE_VAR(argv);
+   USE_VAR(env);
diff --git a/examples/canvas_harness/canvas_harness.html b/examples/canvas_harness/canvas_harness.html
new file mode 100644
index 00000000..a37b6937
--- /dev/null
+++ b/examples/canvas_harness/canvas_harness.html
@@ -0,0 +1,170 @@
+<html>
+<!--
+
+  american fuzzy lop++ - <canvas> harness
+  -------------------------------------
+ 
+  Originally written by Michal Zalewski
+ 
+  Copyright 2013, 2014 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
+ 
+  A simple harness for going through afl-generated test cases, rendering them in
+  the browser environment, and discovering the use of uninitialized memory and
+  similar bugs. This code led to the discovery of a fair number of library and
+  browser security bugs!
+
+  The url_list[] array is a placeholder; for this to work properly, it needs to
+  be initialized with web-reachable paths to individual test cases. This can
+  be done manually or with a simple script.
+
+-->
+
+<body onload="set_images()">
+
+<div id="status"></div>
+
+<div id="image_div"></div>
+
+<canvas height=64 width=64 id=cvs></canvas>
+
+<h2>Results</h2>
+
+<ul id="output"></ul>
+
+<script>
+
+var c = document.getElementById('cvs');
+var ctx = c.getContext('2d');
+
+var url_list = [
+  "images/id:000000,[...].jpg",
+  "images/id:000001,[...].jpg",
+  /* ... */
+  null
+];
+
+var USE_IMAGES = 50;
+var cur_image = 0;
+
+if (location.hash) cur_image = parseInt(location.hash.substr(1));
+
+var loaded = 0;
+var image_obj = [];
+
+var msie_cleanup;
+
+function check_results() {
+
+  var uniques = [];
+
+  clearTimeout(msie_cleanup);
+
+  ctx.clearRect(0, 0, 64, 64);
+
+  uniques.push(image_obj[0].imgdata);
+
+  for (var i = 1; i < USE_IMAGES; i++) {
+
+    if (!image_obj[i].imgdata) continue;
+
+    if (image_obj[0].imgdata != image_obj[i].imgdata) {
+
+      for (var j = 1; j < uniques.length; j++)
+        if (uniques[j] == image_obj[i].imgdata) break;
+
+      if (j == uniques.length) uniques.push(image_obj[i].imgdata);
+
+
+    }
+
+  }
+
+  if (uniques.length > 1) {
+
+    var str = '<li> Image ' + url_list[cur_image] + ' has ' + uniques.length + ' variants: ';
+
+    for (var i = 0; i < uniques.length; i++)
+      str += '<img src="' + uniques[i] + '">';
+
+    document.getElementById('output').innerHTML += str;
+
+  }
+
+  cur_image++;
+  set_images();
+}
+
+
+function count_image() {
+
+  if (!this.complete || this.counted) return;
+
+  this.counted = true;
+
+  loaded++;
+
+  ctx.clearRect(0, 0, 64, 64);
+
+  try {
+    ctx.drawImage(this, 0, 0, 64, 64);
+  } catch (e) { }
+
+  this.imgdata = c.toDataURL();
+
+  if (loaded == USE_IMAGES) check_results();
+}
+
+
+function set_images() {
+
+  loaded = 0;
+
+  document.getElementById('status').innerHTML = 'Now processing ' + cur_image + '...';
+  location.hash = '#' + cur_image;
+
+  if (url_list[cur_image] == null) {
+    alert('Done!');
+    return;
+  }
+
+  restart_images();
+
+  msie_cleanup = setTimeout(check_results, 5000);
+
+  for (var i = 0; i < USE_IMAGES; i++)
+    image_obj[i].src = url_list[cur_image] + '?' + Math.random();
+
+}
+
+
+function restart_images() {
+
+  for (var i = 0; i < USE_IMAGES; i++) 
+    if (image_obj[i]) image_obj[i].counted = true;
+
+  document.getElementById('image_div').innerHTML = '';
+  image_obj = [];
+
+  for (var i = 0; i < USE_IMAGES; i++) {
+
+    image_obj[i] = new Image();
+    image_obj[i].height = 64;
+    image_obj[i].width = 64;
+    image_obj[i].onerror = count_image;
+    image_obj[i].onload = count_image;
+
+    document.getElementById('image_div').appendChild(image_obj[i]);
+
+  }
+
+}
+
+</script>
+
+<iframe src='http://www.cnn.com/'></iframe>
diff --git a/examples/clang_asm_normalize/as b/examples/clang_asm_normalize/as
new file mode 100755
index 00000000..45537cae
--- /dev/null
+++ b/examples/clang_asm_normalize/as
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - clang assembly normalizer
+# ----------------------------------------------
+#
+# Originally written by Michal Zalewski
+# The idea for this wrapper comes from Ryan Govostes.
+#
+# Copyright 2013, 2014 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
+#
+# This 'as' wrapper should allow you to instrument unruly, hand-written
+# assembly with afl-as.
+#
+# Usage:
+#
+# export AFL_REAL_PATH=/path/to/directory/with/afl-as/
+# AFL_PATH=/path/to/this/directory/ make clean all
+
+if [ "$#" -lt "2" ]; then
+  echo "[-] Error: this utility can't be called directly." 1>&2
+  exit 1
+fi
+
+if [ "$AFL_REAL_PATH" = "" ]; then
+  echo "[-] Error: AFL_REAL_PATH not set!" 1>&2
+  exit 1
+fi
+
+if [ ! -x "$AFL_REAL_PATH/afl-as" ]; then
+  echo "[-] Error: AFL_REAL_PATH does not contain the 'afl-as' binary." 1>&2
+  exit 1
+fi
+
+unset __AFL_AS_CMDLINE __AFL_FNAME
+
+while [ ! "$#" = "0" ]; do
+
+  if [ "$#" = "1" ]; then
+    __AFL_FNAME="$1"
+  else
+    __AFL_AS_CMDLINE="${__AFL_AS_CMDLINE} $1"
+  fi
+
+  shift
+
+done
+
+test "$TMPDIR" = "" && TMPDIR=/tmp
+
+TMPFILE=`mktemp $TMPDIR/.afl-XXXXXXXXXX.s`
+
+test "$TMPFILE" = "" && exit 1
+
+clang -cc1as -filetype asm -output-asm-variant 0 "${__AFL_FNAME}" >"$TMPFILE"
+
+ERR="$?"
+
+if [ ! "$ERR" = "0" ]; then
+  rm -f "$TMPFILE"
+  exit $ERR
+fi
+
+"$AFL_REAL_PATH/afl-as" ${__AFL_AS_CMDLINE} "$TMPFILE"
+
+ERR="$?"
+
+rm -f "$TMPFILE"
+
+exit "$ERR"
diff --git a/examples/crash_triage/triage_crashes.sh b/examples/crash_triage/triage_crashes.sh
new file mode 100755
index 00000000..6d026d61
--- /dev/null
+++ b/examples/crash_triage/triage_crashes.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - crash triage utility
+# -----------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2013, 2014, 2017 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
+#
+# Note that this assumes that the targeted application reads from stdin
+# and requires no other cmdline parameters. Modify as needed if this is
+# not the case.
+#
+# Note that on OpenBSD, you may need to install a newer version of gdb
+# (e.g., from ports). You can set GDB=/some/path to point to it if
+# necessary.
+#
+
+echo "crash triage utility for afl-fuzz by Michal Zalewski"
+echo
+
+ulimit -v 100000 2>/dev/null
+ulimit -d 100000 2>/dev/null
+
+if [ "$#" -lt "2" ]; then
+  echo "Usage: $0 /path/to/afl_output_dir /path/to/tested_binary [...target params...]" 1>&2
+  echo 1>&2
+  exit 1
+fi
+
+DIR="$1"
+BIN="$2"
+shift
+shift
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+  echo "$DIR" | grep -qE '^(/var)?/tmp/'
+  T1="$?"
+
+  echo "$BIN" | grep -qE '^(/var)?/tmp/'
+  T2="$?"
+
+  if [ "$T1" = "0" -o "$T2" = "0" ]; then
+    echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+    exit 1
+  fi
+
+fi
+
+if
+ [ "$GDB" = "" ]; then
+  GDB=gdb
+fi
+
+if [ ! -f "$BIN" -o ! -x "$BIN" ]; then
+  echo "[-] Error: binary '$2' not found or is not executable." 1>&2
+  exit 1
+fi
+
+if [ ! -d "$DIR/queue" ]; then
+  echo "[-] Error: directory '$1' not found or not created by afl-fuzz." 1>&2
+  exit 1
+fi
+
+CCOUNT=$((`ls -- "$DIR/crashes" 2>/dev/null | wc -l`))
+
+if [ "$CCOUNT" = "0" ]; then
+  echo "No crashes recorded in the target directory - nothing to be done."
+  exit 0
+fi
+
+echo
+
+for crash in $DIR/crashes/id:*; do
+
+  id=`basename -- "$crash" | cut -d, -f1 | cut -d: -f2`
+  sig=`basename -- "$crash" | cut -d, -f2 | cut -d: -f2`
+
+  # Grab the args, converting @@ to $crash
+
+  use_args=""
+  use_stdio=1
+
+  for a in $@; do
+
+    if [ "$a" = "@@" ] ; then
+      args="$use_args $crash"
+      unset use_stdio
+    else
+      args="$use_args $a"
+    fi
+
+  done
+
+  # Strip the trailing space
+  use_args="${use_args# }"
+
+  echo "+++ ID $id, SIGNAL $sig +++"
+  echo
+
+  if [ "$use_stdio" = "1" ]; then  
+    $GDB --batch -q --ex "r $use_args <$crash" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+  else
+    $GDB --batch -q --ex "r $use_args" --ex 'back' --ex 'disass $pc, $pc+16' --ex 'info reg' --ex 'quit' "$BIN" 0</dev/null
+  fi
+  echo
+
+done
diff --git a/examples/custom_mutators/README b/examples/custom_mutators/README
new file mode 100644
index 00000000..e83baa67
--- /dev/null
+++ b/examples/custom_mutators/README
@@ -0,0 +1,2 @@
+This is a simple example for the AFL_CUSTOM_MUTATOR_LIBRARY feature.
+For more information see docs/custom_mutator.txt
diff --git a/examples/custom_mutators/simple_mutator.c b/examples/custom_mutators/simple_mutator.c
new file mode 100644
index 00000000..bf655679
--- /dev/null
+++ b/examples/custom_mutators/simple_mutator.c
@@ -0,0 +1,49 @@
+/*
+  Simple Custom Mutator for AFL
+
+  Written by Khaled Yakdan <yakdan@code-intelligence.de>
+
+  This a simple mutator that assumes that the generates messages starting with
+  one of the three strings GET, PUT, or DEL followed by a payload. The mutator
+  randomly selects a commend and mutates the payload of the seed provided as
+  input.
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char *commands[] = {
+
+    "GET",
+    "PUT",
+    "DEL",
+
+};
+
+static size_t data_size = 100;
+
+size_t afl_custom_mutator(uint8_t *data, size_t size, uint8_t *mutated_out,
+                          size_t max_size, unsigned int seed) {
+
+  // Seed the PRNG
+  srand(seed);
+
+  // 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;
+
+}
+
diff --git a/examples/distributed_fuzzing/sync_script.sh b/examples/distributed_fuzzing/sync_script.sh
new file mode 100755
index 00000000..c45ae69b
--- /dev/null
+++ b/examples/distributed_fuzzing/sync_script.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+#
+# american fuzzy lop++ - fuzzer synchronization tool
+# --------------------------------------------------
+#
+# Originally written by Michal Zalewski
+#
+# Copyright 2014 Google Inc. All rights reserved.
+# Copyright 2019-2020 AFLplusplus Project. 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
+#
+# To make this script work:
+#
+# - Edit FUZZ_HOSTS, FUZZ_DOMAIN, FUZZ_USER, and SYNC_DIR to reflect your
+#   environment.
+#
+# - Make sure that the system you are running this on can log into FUZZ_HOSTS
+#   without a password (authorized_keys or otherwise).
+#
+# - Make sure that every fuzzer is running with -o pointing to SYNC_DIR and -S
+#   that consists of its local host name, followed by an underscore, and then
+#   by some host-local fuzzer ID.
+#
+
+# Hosts to synchronize the data across.
+FUZZ_HOSTS='host1 host2 host3 host4'
+
+# Domain for all hosts
+FUZZ_DOMAIN='example.com'
+
+# Remote user for SSH
+FUZZ_USER=bob
+
+# Directory to synchronize
+SYNC_DIR='/home/bob/sync_dir'
+
+# Interval (seconds) between sync attempts
+SYNC_INTERVAL=$((30 * 60))
+
+if [ "$AFL_ALLOW_TMP" = "" ]; then
+
+  if [ "$PWD" = "/tmp" -o "$PWD" = "/var/tmp" ]; then
+    echo "[-] Error: do not use shared /tmp or /var/tmp directories with this script." 1>&2
+    exit 1
+  fi
+
+fi
+
+rm -rf .sync_tmp 2>/dev/null
+mkdir .sync_tmp || exit 1
+
+while :; do
+
+  # Pull data in...
+
+  for host in $FUZZ_HOSTS; do
+
+    echo "[*] Retrieving data from ${host}.${FUZZ_DOMAIN}..."
+
+    ssh -o 'passwordauthentication no' ${FUZZ_USER}@${host}.$FUZZ_DOMAIN \
+      "cd '$SYNC_DIR' && tar -czf - ${host}_*/[qf]*" >".sync_tmp/${host}.tgz"
+
+  done
+
+  # Distribute data. For large fleets, see tips in the docs/ directory.
+
+  for dst_host in $FUZZ_HOSTS; do
+
+    echo "[*] Distributing data to ${dst_host}.${FUZZ_DOMAIN}..."
+
+    for src_host in $FUZZ_HOSTS; do
+
+      test "$src_host" = "$dst_host" && continue
+
+      echo "    Sending fuzzer data from ${src_host}.${FUZZ_DOMAIN}..."
+
+      ssh -o 'passwordauthentication no' ${FUZZ_USER}@$dst_host \
+        "cd '$SYNC_DIR' && tar -xkzf -" <".sync_tmp/${src_host}.tgz"
+
+    done
+
+  done
+
+  echo "[+] Done. Sleeping for $SYNC_INTERVAL seconds (Ctrl-C to quit)."
+
+  sleep $SYNC_INTERVAL
+
+done
+
diff --git a/examples/libpng_no_checksum/libpng-nocrc.patch b/examples/libpng_no_checksum/libpng-nocrc.patch
new file mode 100644
index 00000000..0a3793a0
--- /dev/null
+++ b/examples/libpng_no_checksum/libpng-nocrc.patch
@@ -0,0 +1,15 @@
+--- pngrutil.c.orig	2014-06-12 03:35:16.000000000 +0200
++++ pngrutil.c	2014-07-01 05:08:31.000000000 +0200
+@@ -268,7 +268,11 @@
+    if (need_crc != 0)
+    {
+       crc = png_get_uint_32(crc_bytes);
+-      return ((int)(crc != png_ptr->crc));
++
++      if (crc != png_ptr->crc)
++        fprintf(stderr, "NOTE: CRC in the file is 0x%08x, change to 0x%08x\n", crc, png_ptr->crc);
++
++      return ((int)(1 != 1));
+    }
+ 
+    else
diff --git a/examples/persistent_demo/persistent_demo.c b/examples/persistent_demo/persistent_demo.c
new file mode 100644
index 00000000..7d8638fb
--- /dev/null
+++ b/examples/persistent_demo/persistent_demo.c
@@ -0,0 +1,101 @@
+/*
+   american fuzzy lop++ - persistent mode example
+   --------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   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
+
+   This file demonstrates the high-performance "persistent mode" that may be
+   suitable for fuzzing certain fast and well-behaved libraries, provided that
+   they are stateless or that their internal state can be easily reset
+   across runs.
+
+   To make this work, the library and this shim need to be compiled in LLVM
+   mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+/* Main entry point. */
+
+int main(int argc, char** argv) {
+
+  ssize_t len;                               /* how much input did we read? */
+  char buf[100]; /* Example-only buffer, you'd replace it with other global or
+                    local variables appropriate for your use case. */
+
+  /* The number passed to __AFL_LOOP() controls the maximum number of
+     iterations before the loop exits and the program is allowed to
+     terminate normally. This limits the impact of accidental memory leaks
+     and similar hiccups. */
+
+  while (__AFL_LOOP(1000)) {
+
+    /*** PLACEHOLDER CODE ***/
+
+    /* STEP 1: Fully re-initialize all critical variables. In our example, this
+               involves zeroing buf[], our input buffer. */
+
+    memset(buf, 0, 100);
+
+    /* STEP 2: Read input data. When reading from stdin, no special preparation
+               is required. When reading from a named file, you need to close
+               the old descriptor and reopen the file first!
+
+               Beware of reading from buffered FILE* objects such as stdin. Use
+               raw file descriptors or call fopen() / fdopen() in every pass. */
+
+    len = read(0, buf, 100);
+
+    /* STEP 3: This is where we'd call the tested library on the read data.
+               We just have some trivial inline code that faults on 'foo!'. */
+
+    /* do we have enough data? */
+    if (len < 4) return 0;
+
+    if (buf[0] == 'f') {
+
+      printf("one\n");
+      if (buf[1] == 'o') {
+
+        printf("two\n");
+        if (buf[2] == 'o') {
+
+          printf("three\n");
+          if (buf[3] == '!') {
+
+            printf("four\n");
+            abort();
+
+          }
+
+        }
+
+      }
+
+    }
+
+    /*** END PLACEHOLDER CODE ***/
+
+  }
+
+  /* Once the loop is exited, terminate normally - AFL will restart the process
+     when this happens, with a clean slate when it comes to allocated memory,
+     leftover file descriptors, etc. */
+
+  return 0;
+
+}
+
diff --git a/examples/post_library/post_library.so.c b/examples/post_library/post_library.so.c
new file mode 100644
index 00000000..487b9a6d
--- /dev/null
+++ b/examples/post_library/post_library.so.c
@@ -0,0 +1,120 @@
+/*
+   american fuzzy lop++ - postprocessor library example
+   --------------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   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_postprocess() function for every mutated output buffer.
+   From there, you have three choices:
+
+   1) If you don't want to modify the test case, simply return the original
+      buffer pointer ('in_buf').
+
+   2) If you want to skip this test case altogether and have AFL generate a
+      new one, return 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. You can update *len if necessary, too.
+
+      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).
+
+      *** DO NOT MODIFY THE ORIGINAL 'in_buf' BUFFER. ***
+
+    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"
+
+/* The actual postprocessor routine called by afl-fuzz: */
+
+const unsigned char* afl_postprocess(const unsigned char* in_buf,
+                                     unsigned int*        len) {
+
+  static unsigned char* saved_buf;
+  unsigned char*        new_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 NULL;
+
+  /* Do nothing for buffers that already start with the expected header. */
+
+  if (!memcmp(in_buf, HEADER, strlen(HEADER))) return in_buf;
+
+  /* Allocate memory for new buffer, reusing previous allocation if
+     possible. */
+
+  new_buf = realloc(saved_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 (!new_buf) return in_buf;
+  saved_buf = new_buf;
+
+  /* Copy the original data to the new location. */
+
+  memcpy(new_buf, in_buf, *len);
+
+  /* Insert the new header. */
+
+  memcpy(new_buf, HEADER, strlen(HEADER));
+
+  /* Return modified buffer. No need to update *len in this particular case,
+     as we're not changing it. */
+
+  return new_buf;
+
+}
+
diff --git a/examples/post_library/post_library_png.so.c b/examples/post_library/post_library_png.so.c
new file mode 100644
index 00000000..43cb1101
--- /dev/null
+++ b/examples/post_library/post_library_png.so.c
@@ -0,0 +1,114 @@
+/*
+   american fuzzy lop++ - postprocessor for PNG
+   ------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   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
+
+   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)
+
+const unsigned char* afl_postprocess(const unsigned char* in_buf,
+                                     unsigned int*        len) {
+
+  static unsigned char* saved_buf;
+  static unsigned int   saved_len;
+
+  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) return in_buf;
+
+  /* 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 <= saved_len) {
+
+          new_buf = saved_buf;
+
+        } else {
+
+          new_buf = realloc(saved_buf, UP4K(*len));
+          if (!new_buf) return in_buf;
+          saved_buf = new_buf;
+          saved_len = 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;
+
+  }
+
+  return new_buf;
+
+}
+
diff --git a/examples/python_mutators/README b/examples/python_mutators/README
new file mode 100644
index 00000000..4e7d62bc
--- /dev/null
+++ b/examples/python_mutators/README
@@ -0,0 +1,18 @@
+These are example and helper files for the AFL_PYTHON_MODULE feature.
+See docs/python_mutators.txt for more information
+
+Note that if you compile with python3.7 you must use python3 scripts, and if
+you use pyton2.7 to compile python2 scripts!
+
+
+example.py	- this is the template you can use, the functions are there
+		  but they are empty
+
+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
diff --git a/examples/python_mutators/XmlMutatorMin.py b/examples/python_mutators/XmlMutatorMin.py
new file mode 100644
index 00000000..058b7e61
--- /dev/null
+++ b/examples/python_mutators/XmlMutatorMin.py
@@ -0,0 +1,331 @@
+#!/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/python_mutators/common.py b/examples/python_mutators/common.py
new file mode 100644
index 00000000..28b8ee80
--- /dev/null
+++ b/examples/python_mutators/common.py
@@ -0,0 +1,37 @@
+#!/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/python_mutators/example.py b/examples/python_mutators/example.py
new file mode 100644
index 00000000..d32a7eb2
--- /dev/null
+++ b/examples/python_mutators/example.py
@@ -0,0 +1,103 @@
+#!/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
+
+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)
+    return 0
+
+def fuzz(buf, add_buf):
+    '''
+    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.
+    
+    @rtype: bytearray
+    @return: A new bytearray containing the mutated data
+    '''
+    ret = bytearray(buf)
+    # Do something interesting with ret
+
+    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
diff --git a/examples/python_mutators/simple-chunk-replace.py b/examples/python_mutators/simple-chunk-replace.py
new file mode 100644
index 00000000..218dd4f8
--- /dev/null
+++ b/examples/python_mutators/simple-chunk-replace.py
@@ -0,0 +1,59 @@
+#!/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)
+    return 0
+
+def fuzz(buf, add_buf):
+    '''
+    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.
+    
+    @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/python_mutators/wrapper_afl_min.py b/examples/python_mutators/wrapper_afl_min.py
new file mode 100644
index 00000000..df09b40a
--- /dev/null
+++ b/examples/python_mutators/wrapper_afl_min.py
@@ -0,0 +1,117 @@
+#!/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):
+    """
+          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:
+            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:
+            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:
+        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:
+        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)
+
diff --git a/examples/socket_fuzzing/Makefile b/examples/socket_fuzzing/Makefile
new file mode 100644
index 00000000..0191ba53
--- /dev/null
+++ b/examples/socket_fuzzing/Makefile
@@ -0,0 +1,39 @@
+#
+# american fuzzy lop++ - socket_fuzz
+# ----------------------------------
+#
+# 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
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+ifneq "$(filter Linux GNU%,$(shell uname))" ""
+  LDFLAGS  += -ldl
+endif
+
+all: socketfuzz32.so socketfuzz64.so
+
+socketfuzz32.so: socketfuzz.c
+	-$(CC) -m32 $(CFLAGS) $^ $(LDFLAGS) -o $@ || echo "socketfuzz32 build failure (that's fine)"
+
+socketfuzz64.so: socketfuzz.c
+	-$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+install: socketfuzz32.so socketfuzz64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f socketfuzz32.so ]; then set -e; install -m 755 socketfuzz32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	install -m 755 socketfuzz64.so $(DESTDIR)$(HELPER_PATH)/
+
+clean:
+	rm -f socketfuzz32.so socketfuzz64.so
diff --git a/examples/socket_fuzzing/README.md b/examples/socket_fuzzing/README.md
new file mode 100644
index 00000000..79f28bea
--- /dev/null
+++ b/examples/socket_fuzzing/README.md
@@ -0,0 +1,11 @@
+# socketfuzz
+
+when you want to fuzz a network service and you can not/do not want to modify
+the source (or just have a binary), then this LD_PRELOAD library will allow
+for sending input to stdin which the target binary will think is coming from
+a network socket.
+
+This is desock_dup.c from the amazing preeny project
+https://github.com/zardus/preeny
+
+It is packaged in afl++ to have it at hand if needed
diff --git a/examples/socket_fuzzing/socketfuzz.c b/examples/socket_fuzzing/socketfuzz.c
new file mode 100644
index 00000000..3ec8383b
--- /dev/null
+++ b/examples/socket_fuzzing/socketfuzz.c
@@ -0,0 +1,110 @@
+/*
+ * This is desock_dup.c from the amazing preeny project
+ * https://github.com/zardus/preeny
+ *
+ * It is packaged in afl++ to have it at hand if needed
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>   //
+#include <sys/socket.h>  //
+#include <sys/stat.h>    //
+#include <fcntl.h>       //
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <poll.h>
+//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: "
+
+//
+// originals
+//
+int (*original_close)(int);
+int (*original_dup2)(int, int);
+__attribute__((constructor)) void preeny_desock_dup_orig() {
+
+  original_close = dlsym(RTLD_NEXT, "close");
+  original_dup2 = dlsym(RTLD_NEXT, "dup2");
+
+}
+
+int close(int sockfd) {
+
+  if (sockfd <= 2) {
+
+    fprintf(stderr, "Info: Disabling close on %d\n", sockfd);
+    return 0;
+
+  } else {
+
+    return original_close(sockfd);
+
+  }
+
+}
+
+int dup2(int old, int new) {
+
+  if (new <= 2) {
+
+    fprintf(stderr, "Info: Disabling dup from %d to %d\n", old, new);
+    return 0;
+
+  } else {
+
+    return original_dup2(old, new);
+
+  }
+
+}
+
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+
+  (void)sockfd;
+  (void)addr;
+  (void)addrlen;
+  fprintf(stderr, "Info: Emulating accept on %d\n", sockfd);
+  return 0;
+
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+
+  (void)sockfd;
+  (void)addr;
+  (void)addrlen;
+  fprintf(stderr, "Info: Emulating bind on port %d\n",
+          ntohs(((struct sockaddr_in *)addr)->sin_port));
+  return 0;
+
+}
+
+int listen(int sockfd, int backlog) {
+
+  (void)sockfd;
+  (void)backlog;
+  return 0;
+
+}
+
+int setsockopt(int sockfd, int level, int optid, const void *optdata,
+               socklen_t optdatalen) {
+
+  (void)sockfd;
+  (void)level;
+  (void)optid;
+  (void)optdata;
+  (void)optdatalen;
+  return 0;
+
+}
+